springcloud_k8s_panzhihuazhihuishequ/applets/src/main/java/com/panzhihua/applets/api/UserApi.java
@@ -6,6 +6,8 @@ import com.panzhihua.applets.model.dtos.ComPbMemberCertificationDTO; import com.panzhihua.common.constants.UserConstants; import com.panzhihua.common.model.dtos.shop.ExcelShopOrderDTO; import com.panzhihua.common.constants.SecurityConstants; import com.panzhihua.common.constants.UserConstants; import com.panzhihua.common.model.dtos.user.SysUserEditTipsDTO; import com.panzhihua.common.model.dtos.user.SysUserFeedbackDTO; import com.panzhihua.common.model.vos.community.*; @@ -52,6 +54,8 @@ private PartyBuildingService partyBuildingService; @Resource private CheckService checkService; @Resource private StringRedisTemplate stringRedisTemplate; @ApiOperation(value = "当前登录用户信息", response = LoginUserInfoVO.class) @GetMapping("info") @@ -119,6 +123,11 @@ if (R.isOk(r1)) { log.info("新增实名认证未通过通知成功【{}】", JSONObject.toJSONString(sysUserNoticeVO)); } //清空缓存 String userRoleKey = UserConstants.LOGIN_USER_INFO + this.getLoginUserInfo().getUserId(); String userAppletRoleKey = SecurityConstants.ROLE_APPLETS_USER + this.getLoginUserInfo().getUserId(); stringRedisTemplate.delete(userRoleKey); stringRedisTemplate.delete(userAppletRoleKey); } else { //未通过发通知 /** springcloud_k8s_panzhihuazhihuishequ/common/src/main/java/com/panzhihua/common/constants/SecurityConstants.java
@@ -16,5 +16,6 @@ public static final String APPLETS_ACCESS_MEDIA_ID ="APPLETS_ACCESS_MEDIA_ID";//小程序获取的access_token public static final String APPLETS_ACCESS_MEDIA_ID_TIME ="APPLETS_ACCESS_MEDIA_ID_TIME";//小程序获取的access_token public static final String ROLE_APPLETS_REAL_NAMED="applets:realnamed";//小程序用户实名角色 public static final String ROLE_APPLETS_USER="applets:realnamed:user:";//小程序用户角色 } springcloud_k8s_panzhihuazhihuishequ/service_user/src/main/java/com/panzhihua/service_user/service/impl/UserServiceImpl.java
@@ -253,6 +253,7 @@ loginUserInfoVO.setIsmemberrole(1); } } loginUserInfoVO.setIsRealNamed(sysUserDO.getIdCard()!=null); return R.ok(loginUserInfoVO); } springcloud_k8s_panzhihuazhihuishequ/zuul/src/main/java/com/panzhihua/zuul/config/AppletWebSecurityConfigurationAdapter.java
New file @@ -0,0 +1,29 @@ package com.panzhihua.zuul.config; import com.panzhihua.common.constants.SecurityConstants; import com.panzhihua.zuul.filters.AppletAuthenticationFilter; import org.springframework.boot.autoconfigure.security.SecurityProperties; import org.springframework.context.annotation.Configuration; import org.springframework.core.annotation.Order; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.web.authentication.AnonymousAuthenticationFilter; /** * @ClasssName AppletWebSecurityConfigurationAdapter * @Description 小程序 * @Author cedoo * @Date 2021/4/30 * @Version 1.0 **/ @Configuration @Order(SecurityProperties.BASIC_AUTH_ORDER-2) public class AppletWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.antMatcher("/api/applets/**").authorizeRequests() .anyRequest().hasAnyRole(SecurityConstants.ROLE_APPLETS) .and() .addFilterAfter(new AppletAuthenticationFilter(), AnonymousAuthenticationFilter.class); } } springcloud_k8s_panzhihuazhihuishequ/zuul/src/main/java/com/panzhihua/zuul/config/RealNamedConfig.java
New file @@ -0,0 +1,17 @@ package com.panzhihua.zuul.config; import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; import java.util.List; @Component @ConfigurationProperties(prefix = "applet.realname") @Data public class RealNamedConfig { private List<String> verify; } springcloud_k8s_panzhihuazhihuishequ/zuul/src/main/java/com/panzhihua/zuul/config/SpringSecurityConfig.java
@@ -1,10 +1,14 @@ package com.panzhihua.zuul.config; import com.panzhihua.zuul.filters.AppletAuthenticationFilter; import com.panzhihua.zuul.filters.JWTAuthenticationTokenFilter; import com.panzhihua.zuul.filters.SercuritFilter; import com.panzhihua.zuul.handles.UserAuthAccessDeniedHandler; import com.panzhihua.zuul.manager.RoleAccessDecisionManager; import org.springframework.boot.autoconfigure.security.SecurityProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.annotation.Order; import org.springframework.security.config.annotation.ObjectPostProcessor; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; @@ -12,6 +16,7 @@ import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.web.access.intercept.FilterSecurityInterceptor; import org.springframework.security.web.authentication.AnonymousAuthenticationFilter; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import javax.annotation.Resource; @@ -23,6 +28,7 @@ **/ @Configuration @EnableWebSecurity @Order(SecurityProperties.BASIC_AUTH_ORDER-1) public class SpringSecurityConfig extends WebSecurityConfigurerAdapter { @Resource @@ -34,6 +40,7 @@ */ @Resource private UserAuthAccessDeniedHandler userAuthAccessDeniedHandler; @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() @@ -56,9 +63,6 @@ // 禁用缓存 http.headers().cacheControl(); http.addFilterBefore(new JWTAuthenticationTokenFilter(), AnonymousAuthenticationFilter.class); } } springcloud_k8s_panzhihuazhihuishequ/zuul/src/main/java/com/panzhihua/zuul/filters/AppletAuthenticationFilter.java
New file @@ -0,0 +1,132 @@ package com.panzhihua.zuul.filters; import com.alibaba.fastjson.JSONArray; import com.panzhihua.common.constants.*; import com.panzhihua.common.model.vos.R; import com.panzhihua.common.utlis.JWTTokenUtil; import com.panzhihua.common.utlis.ResultUtil; import com.panzhihua.zuul.config.RealNamedConfig; import io.jsonwebtoken.Claims; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.core.ValueOperations; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.stereotype.Component; import org.springframework.web.context.support.WebApplicationContextUtils; import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; /** * @program: springcloud_k8s_panzhihuazhihuishequ * @description: 小程序权限验证 * @author: huang.hongfa weixin hhf9596 qq 959656820 * @create: 2020-11-25 16:35 **/ @Component public class AppletAuthenticationFilter implements Filter { private StringRedisTemplate stringRedisTemplate; @Autowired private RealNamedConfig realNamedConfig; @Override public void init(FilterConfig filterConfig) throws ServletException { } /** * 用户是否登录校验 * * @param servletRequest 请求 * @param servletResponse 返回 * @param filterChain 过滤器链条 * @throws IOException io * @throws ServletException servlet */ @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) servletRequest; SafeboxRequestWrapper safeboxRequestWrapper = new SafeboxRequestWrapper(request); HttpServletResponse response = (HttpServletResponse) servletResponse; // 获取请求头中JWT的Token String tokenHeader = request.getHeader(TokenConstant.TOKEN_HEADER); if (null != tokenHeader && tokenHeader.startsWith(TokenConstant.TOKEN_PRE)) { String token = tokenHeader.replace(TokenConstant.TOKEN_PRE, ""); // token解析 Claims claims = JWTTokenUtil.getClaimsFromToken(token); String username = claims.getSubject(); int type = (Integer) claims.get("type"); if (1 == type) {//小程序用户统一角色 String requestURI = request.getRequestURI(); String requestMethod = request.getMethod().toLowerCase(); ServletContext context = request.getServletContext(); ApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(context); stringRedisTemplate = ctx.getBean(StringRedisTemplate.class); ValueOperations<String, String> valueOperations = stringRedisTemplate.opsForValue(); String appletUserRoleKey = SecurityConstants.ROLE_APPLETS_USER + username; Boolean userHasRole = stringRedisTemplate.hasKey(appletUserRoleKey); boolean needCheck = false; List<String> checkedUrl = realNamedConfig.getVerify(); checkedUrl = checkedUrl!=null?checkedUrl:new ArrayList<>(); for (int i = 0; i < checkedUrl.size(); i++) { String url = checkedUrl.get(i); if (url.toLowerCase().startsWith(requestMethod) && url.endsWith(requestURI)) { needCheck = true; } else { continue; } } if (needCheck) { if (userHasRole) { boolean userHashRight = false; try { String roles = valueOperations.get(appletUserRoleKey); List<SimpleGrantedAuthority> authorities = JSONArray.parseArray(roles, SimpleGrantedAuthority.class); if (authorities != null && authorities.size() > 0) { AtomicBoolean userHasRightRole = new AtomicBoolean(false); authorities.forEach(authority -> { if (authority.getAuthority().equals(SecurityConstants.ROLE_APPLETS_REAL_NAMED)) { userHasRightRole.set(true); } }); if (userHasRightRole.get()) { //用户包含“已实名”角色,则放行 什么也不做 userHashRight = true; } } } catch (Exception e) { userHashRight = false; } if (!userHashRight) { ResultUtil.responseJson(response, R.fail(HttpStatus.FORBIDDEN, "用户未实名")); return; } }else{ ResultUtil.responseJson(response, R.fail(HttpStatus.FORBIDDEN, "用户未实名")); return; } } } } filterChain.doFilter(safeboxRequestWrapper, response); } @Override public void destroy() { } } springcloud_k8s_panzhihuazhihuishequ/zuul/src/main/java/com/panzhihua/zuul/filters/JWTAuthenticationTokenFilter.java
@@ -122,11 +122,28 @@ } List<SimpleGrantedAuthority> authorities = new ArrayList<>(); List<SimpleGrantedAuthority> authorities1 = new ArrayList<>(); if (1 == type) {//小程序用户统一角色 String roleAppletKey = SecurityConstants.ROLE_APPLETS_USER +username; if(stringRedisTemplate.hasKey(roleAppletKey)){ String roles = valueOperations.get(roleAppletKey); authorities = JSONArray.parseArray(roles, SimpleGrantedAuthority.class); }else { authorities.add(new SimpleGrantedAuthority(SecurityConstants.ROLE_APPLETS)); String userKey = UserConstants.LOGIN_USER_INFO + username; Boolean hasKeyLoginUserInfo = stringRedisTemplate.hasKey(userKey); if (hasKeyLoginUserInfo) { String userInfo = valueOperations.get(userKey); LoginUserInfoVO loginUserInfoVO = JSONObject.parseObject(userInfo, LoginUserInfoVO.class); //判断用户是否已实名制 if (loginUserInfoVO.getIsRealNamed() != null && loginUserInfoVO.getIsRealNamed()) { authorities.add(new SimpleGrantedAuthority(SecurityConstants.ROLE_APPLETS_REAL_NAMED)); } } valueOperations.set(roleAppletKey, JSONArray.toJSONString(authorities), 24, TimeUnit.HOURS); } } else { String key = SecurityConstants.ROLE_USER + username; Boolean aBoolean = stringRedisTemplate.hasKey(key); if (1 == type) {//小程序用户统一角色 authorities.add(new SimpleGrantedAuthority(SecurityConstants.ROLE_APPLETS)); } else { if (aBoolean) { String roles = valueOperations.get(key); authorities = JSONArray.parseArray(roles, SimpleGrantedAuthority.class); springcloud_k8s_panzhihuazhihuishequ/zuul/src/main/resources/bootstrap.yml
@@ -28,5 +28,60 @@ service-url: defaultZone: http://${EUREKA_URL:localhost}:8192/eureka # applet 需实名认证的接口地址 applet: realname: verify: - POST:/api/applets/house - POST:/api/applets/putHouse - POST:/api/applets/undercarriageHouse - GET:/api/applets/delHouse - POST:/api/applets/questnaire/add - GET:/api/applets/questnaire/delete - POST:/api/applets/questnaire/edit - GET:/api/applets/questnaire/stat/details - POST:/api/applets/questnaire/toggle - POST:/api/applets/questnaire/stat/answer - POST:/api/applets/index/comacteasyphotocomment - POST:/api/applets/index/commentsign - POST:/api/applets/index/addmessageback - POST:/api/applets/index/addmessage - POST:/api/applets/index/easyphoto - PUT:/api/applets/index/easyphoto - POST:/api/applets/index/microwish - PUT:/api/applets/index/microwish - POST:/api/applets/discuss - POST:/api/applets/discusscommentback - PUT:/api/applets/discusscommentuser - POST:/api/applets/discussuser - PUT:/api/applets/discussuser - POST:/api/applets/neighbor/addNeighborByApp - POST:/api/applets/neighbor/cancel/fabulous - POST:/api/applets/neighbor/comment - POST:/api/applets/neighbor/fabulous - POST:/api/applets/neighbor/reply - PUT:/api/applets/community/signactivity - POST:/api/applets/community/volunteer - POST:/api/applets/user/houses - POST:/api/appletsbackstage/common/data/car/save - DELETE:/api/appletsbackstage/common/data/car/delete - POST:/api/applets/community/car/register - PUT:/api/applets/partybuilding/activitysignup - GET:/api/applets/questnaire/stat - GET:/api/applets/questnaire/view - POST:/api/applets/user/addfamily - PUT:/api/applets/user/putfamily - POST:/api/applets/user/getUserArchives - POST:/api/applets/user/updateUserArchives - POST:/api/applets/user/partybuildingembercertification - GET:/api/applets/user/partybuildingembercertification - GET:/api/applets/index/pagemymessage - POST:/api/applets/index/pagemymessage - POST:/api/applets/user/listactivity - POST:/api/applets/partybuilding/activityinfo - PUT:/api/applets/user/microwishconfirm - POST:/api/applets/user/pagemicrowish - POST:/api/applets/index/pageeasyphoto - POST:/api/applets/user/pageeasyphoto - POST:/api/applets/neighbor/user/page - POST:/api/applets/pagehouse