| | |
| | | //package com.gkhy.safePlatform.config.security; |
| | | // |
| | | //import com.alibaba.fastjson.JSONArray; |
| | | //import com.alibaba.fastjson.JSONObject; |
| | | //import com.gkhy.safePlatform.account.model.cache.CacheUser; |
| | | //import com.gkhy.safePlatform.account.rpc.apimodel.NameService; |
| | | //import com.gkhy.safePlatform.commons.config.token.TokenConfig; |
| | | //import com.gkhy.safePlatform.commons.enums.RedisKeyEnum; |
| | | //import com.gkhy.safePlatform.commons.enums.ResultCodes; |
| | | //import com.gkhy.safePlatform.commons.exception.BusinessException; |
| | | //import com.gkhy.safePlatform.commons.utils.RedisUtils; |
| | | //import com.gkhy.safePlatform.commons.utils.StringUtils; |
| | | //import com.gkhy.safePlatform.commons.vo.ResultVO; |
| | | //import org.apache.dubbo.config.annotation.DubboReference; |
| | | //import org.springframework.beans.factory.annotation.Autowired; |
| | | //import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; |
| | | //import org.springframework.security.core.GrantedAuthority; |
| | | //import org.springframework.security.core.authority.SimpleGrantedAuthority; |
| | | //import org.springframework.security.core.context.SecurityContextHolder; |
| | | //import org.springframework.stereotype.Component; |
| | | //import org.springframework.web.filter.OncePerRequestFilter; |
| | | // |
| | | //import javax.servlet.FilterChain; |
| | | //import javax.servlet.ServletException; |
| | | //import javax.servlet.http.HttpServletRequest; |
| | | //import javax.servlet.http.HttpServletResponse; |
| | | //import java.io.IOException; |
| | | //import java.io.PrintWriter; |
| | | //import java.util.ArrayList; |
| | | //import java.util.List; |
| | | // |
| | | ///** |
| | | //* @Description: token登录过滤器 |
| | | //*/ |
| | | //@Component |
| | | //public class TokenAuthenticationFilter extends OncePerRequestFilter { |
| | | // |
| | | // @Autowired |
| | | // private TokenConfig tokenConfig; |
| | | // @Autowired |
| | | // private RedisUtils redisUtil; |
| | | // @DubboReference(check = false) |
| | | // private NameService nameService; |
| | | // |
| | | // |
| | | // |
| | | // @Override |
| | | // protected void doFilterInternal(HttpServletRequest req, HttpServletResponse resp, FilterChain chain) throws IOException, ServletException { |
| | | // |
| | | // try { |
| | | // //获取当前认证成功用户权限信息 |
| | | // UsernamePasswordAuthenticationToken authRequest = getAuthentication(req, resp); |
| | | // if (authRequest != null) { |
| | | // SecurityContextHolder.getContext().setAuthentication(authRequest); |
| | | // } |
| | | // // 执行下一个 filter 过滤器链 |
| | | // chain.doFilter(req, resp); |
| | | // } catch (BusinessException e) { |
| | | // // 返回异常 |
| | | // this.writeJSON(req, resp, new ResultVO<>(e.getError())); |
| | | // } catch (Exception e) { |
| | | // e.printStackTrace(); |
| | | // this.writeJSON(req, resp, new ResultVO<>(ResultCodes.SERVER_ERROR)); |
| | | // } |
| | | // |
| | | // |
| | | // } |
| | | // |
| | | // |
| | | // private UsernamePasswordAuthenticationToken getAuthentication(HttpServletRequest req,HttpServletResponse resp) { |
| | | // // header获取token |
| | | // String authToken = req.getHeader(tokenConfig.getHeader()); |
| | | // String loginUserId = req.getHeader(tokenConfig.getLoginUserHeader()); |
| | | // |
| | | // if(authToken != null) { |
| | | // // header 传入 userId |
| | | // if (StringUtils.isBlank(loginUserId)) { |
| | | // throw new BusinessException(ResultCodes.CLIENT_CREDENTIALS_LACK); |
| | | // } |
| | | // // 登录成功时,会将权限数据存入redis |
| | | // // 这里是验证获取权限信息 |
| | | // // 1.从redis中获取对应该用户的权限信息 |
| | | // String accessTokenKey = RedisKeyEnum.authKey(RedisKeyEnum.AUTH_TOKEN, loginUserId); |
| | | // Object o = redisUtil.get(accessTokenKey); |
| | | // // 2.token是否存在 |
| | | // if (o == null) { |
| | | // // 是否存在 |
| | | // throw new BusinessException(ResultCodes.CLIENT_CREDENTIALS_SIGN_INVALID); |
| | | // }else{ |
| | | // Long userId = Long.valueOf(loginUserId); |
| | | // CacheUser cacheUser = JSONObject.parseObject(o.toString(), CacheUser.class); |
| | | // assert userId.equals(cacheUser.getUserId()); |
| | | // if ( !authToken.equals(cacheUser.getAccessToken())) { |
| | | // throw new BusinessException(ResultCodes.CLIENT_CREDENTIALS_TOKEN_INVALID); |
| | | // } |
| | | // |
| | | // // 3.redis获取权限 |
| | | // String authoritiesKey = RedisKeyEnum.authKey(RedisKeyEnum.AUTH_AUTHORITIES, userId); |
| | | // Object oo = redisUtil.get(authoritiesKey); |
| | | // List<GrantedAuthority> authorities; |
| | | // // 4.redis中是否存在 |
| | | // if (oo != null) { |
| | | // // 5.存在 |
| | | // String json = oo.toString(); |
| | | // authorities = JSONArray.parseArray(json, GrantedAuthority.class); |
| | | // }else { |
| | | // authorities = new ArrayList<>(); |
| | | // // 6.不存在=>数据库查询 |
| | | // List<String> roleCodes = nameService.getUserRoleCodeByUserId(userId); |
| | | // // role |
| | | // for (String roleCode : roleCodes) { |
| | | // SimpleGrantedAuthority simpleGrantedAuthority = new SimpleGrantedAuthority("ROLE_" + roleCode); |
| | | // authorities.add(simpleGrantedAuthority); |
| | | // } |
| | | // |
| | | // // permission |
| | | // List<String> permissions = nameService.getUserPermissionByUserId(userId); |
| | | // for (String permission : permissions) { |
| | | // SimpleGrantedAuthority simpleGrantedAuthority = new SimpleGrantedAuthority(permission); |
| | | // authorities.add(simpleGrantedAuthority); |
| | | // } |
| | | // } |
| | | // |
| | | // // security对象中存入登陆者信息 |
| | | // return new UsernamePasswordAuthenticationToken(userId,authToken,authorities); |
| | | // |
| | | // } |
| | | // |
| | | // |
| | | // |
| | | // |
| | | // |
| | | // |
| | | // } |
| | | // return null; |
| | | // } |
| | | // |
| | | // |
| | | // |
| | | // protected void writeJSON(HttpServletRequest req, |
| | | // HttpServletResponse resp, |
| | | // ResultVO resultVO) throws IOException { |
| | | // // 设置编码格式 |
| | | // resp.setContentType("text/json;charset=utf-8"); |
| | | // // 处理跨域问题 |
| | | // resp.setHeader("Access-Control-Allow-Origin", "*"); |
| | | // resp.setHeader("Access-Control-Allow-Methods", "POST, GET"); |
| | | // |
| | | // //输出JSON |
| | | // PrintWriter out = resp.getWriter(); |
| | | // out.write(JSONObject.toJSONString(resultVO)); |
| | | // out.flush(); |
| | | // out.close(); |
| | | // } |
| | | //} |
| | | package com.gkhy.safePlatform.config.security; |
| | | |
| | | import com.alibaba.fastjson.JSONArray; |
| | | import com.alibaba.fastjson.JSONObject; |
| | | import com.gkhy.safePlatform.account.rpc.apimodel.AccountAuthService; |
| | | import com.gkhy.safePlatform.account.rpc.apimodel.AccountAuthService; |
| | | import com.gkhy.safePlatform.commons.co.ContextCacheAuthority; |
| | | import com.gkhy.safePlatform.commons.co.ContextCacheUser; |
| | | import com.gkhy.safePlatform.commons.enums.RedisKeyEnum; |
| | | import com.gkhy.safePlatform.commons.enums.ResultCodes; |
| | | import com.gkhy.safePlatform.commons.exception.BusinessException; |
| | | import com.gkhy.safePlatform.commons.utils.RPCUtils; |
| | | import com.gkhy.safePlatform.commons.utils.RequestContextHolder; |
| | | import com.gkhy.safePlatform.commons.utils.StringUtils; |
| | | import com.gkhy.safePlatform.commons.vo.ResultVO; |
| | | import com.gkhy.safePlatform.config.redis.RedisUtils; |
| | | import org.apache.dubbo.config.annotation.DubboReference; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; |
| | | import org.springframework.security.core.GrantedAuthority; |
| | | import org.springframework.security.core.authority.SimpleGrantedAuthority; |
| | | import org.springframework.security.core.context.SecurityContextHolder; |
| | | import org.springframework.stereotype.Component; |
| | | import org.springframework.web.filter.OncePerRequestFilter; |
| | | |
| | | import javax.servlet.FilterChain; |
| | | import javax.servlet.ServletException; |
| | | import javax.servlet.http.HttpServletRequest; |
| | | import javax.servlet.http.HttpServletResponse; |
| | | import java.io.IOException; |
| | | import java.io.PrintWriter; |
| | | import java.util.ArrayList; |
| | | import java.util.Collections; |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * @Description: token登录过滤器 |
| | | */ |
| | | @Component |
| | | public class TokenAuthenticationFilter extends OncePerRequestFilter { |
| | | |
| | | @Autowired |
| | | private TokenConfig tokenConfig; |
| | | @DubboReference(check = false) |
| | | private AccountAuthService userAccountService; |
| | | @Autowired |
| | | private RedisUtils redisUtils; |
| | | |
| | | |
| | | |
| | | @Override |
| | | protected void doFilterInternal(HttpServletRequest req, HttpServletResponse resp, FilterChain chain) throws IOException, ServletException { |
| | | |
| | | try { |
| | | //获取当前认证成功用户权限信息 |
| | | UsernamePasswordAuthenticationToken authRequest = getAuthentication(req, resp); |
| | | if (authRequest != null) { |
| | | SecurityContextHolder.getContext().setAuthentication(authRequest); |
| | | } |
| | | // 执行下一个 filter 过滤器链 |
| | | chain.doFilter(req, resp); |
| | | } catch (BusinessException e) { |
| | | // 返回异常 |
| | | this.writeJSON(req, resp, new ResultVO<>(e.getCode(),e.getMessage())); |
| | | } |
| | | |
| | | } |
| | | |
| | | |
| | | private UsernamePasswordAuthenticationToken getAuthentication(HttpServletRequest req,HttpServletResponse resp) { |
| | | // header获取token |
| | | String authToken = req.getHeader(tokenConfig.getHeader()); |
| | | if(authToken != null) { |
| | | // 登录成功时,会将权限数据存入redis |
| | | // 这里是验证获取权限信息 |
| | | // 1.从redis中获取对应该用户的权限信息 |
| | | String accessTokenKey = RedisKeyEnum.authKey(RedisKeyEnum.AUTH_TOKEN, authToken); |
| | | Object o = redisUtils.get(accessTokenKey); |
| | | // 2.token是否存在 |
| | | if (o == null) { |
| | | // 是否存在 uid未登录 |
| | | throw new BusinessException(ResultCodes.CLIENT_CREDENTIALS_TOKEN_INVALID); |
| | | }else{ |
| | | // todo 可以不转换,建议rpc传入string |
| | | String uid = o.toString(); |
| | | Long userId = Long.valueOf(uid); |
| | | String accessUserKey = RedisKeyEnum.authKey(RedisKeyEnum.AUTH_USER, userId); |
| | | // 这里不做用户信息的token判断 放入登录 |
| | | Long expireSecondsLeft = redisUtils.getExpireTime(accessTokenKey); |
| | | // 60m 内请求则续期 时长为原本的有效时间 |
| | | if (expireSecondsLeft != null && 0L < expireSecondsLeft && expireSecondsLeft < 60 * 60) { |
| | | // 重置token:uid |
| | | redisUtils.resetKeyExpireTime(accessTokenKey, tokenConfig.getExpiration()); |
| | | // 重置uid:userInfo |
| | | redisUtils.resetKeyExpireTime(accessUserKey, tokenConfig.getExpiration()); |
| | | } |
| | | // 获取用户信息 |
| | | Object oo = redisUtils.get(accessUserKey); |
| | | // 初始化 |
| | | ContextCacheUser contextCacheUser = null; |
| | | if (oo == null) { |
| | | // 业务逻辑上是不会空的 |
| | | // 实际操作可能会手动清空 |
| | | ResultVO<ContextCacheUser> rpcResultVo = userAccountService.getCacheUserDetailByUid(userId); |
| | | // 调用rpc返回的数据 没有token 所以得至少续上这次token |
| | | contextCacheUser = this.getRpcResult(rpcResultVo); |
| | | // 因为手动清空等原因,可能会丢失其他token数据,就不去一一搜索这个uid的token了 |
| | | contextCacheUser.setAccessToken(Collections.singletonList(authToken)); |
| | | }else{ |
| | | // 正常的实际场景必定会走这里 |
| | | // 推荐用jackson |
| | | contextCacheUser = JSONObject.parseObject(oo.toString(), ContextCacheUser.class); |
| | | } |
| | | // threadLocal存入用户信息 |
| | | RequestContextHolder.contextUserLocal.set(contextCacheUser); |
| | | // security对象中存入登陆者信息 |
| | | return new UsernamePasswordAuthenticationToken(contextCacheUser, authToken, contextCacheUser.getAuthorities()); |
| | | |
| | | } |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | /** |
| | | * 获取rpc 返回的用户数据 |
| | | * |
| | | * @param rpcResultVo rpc返回数据 |
| | | * @return 用户准备缓存的数据 |
| | | */ |
| | | private ContextCacheUser getRpcResult(ResultVO<ContextCacheUser> rpcResultVo) { |
| | | if (!rpcResultVo.getCode().equals(ResultCodes.OK.getCode())) { |
| | | throw new BusinessException(rpcResultVo.getCode(), rpcResultVo.getMsg()); |
| | | } |
| | | if (rpcResultVo.getData() == null) { |
| | | throw new BusinessException(ResultCodes.RPC_DATA_NULL); |
| | | } |
| | | if (rpcResultVo.getData() instanceof ContextCacheUser) { |
| | | return (ContextCacheUser) rpcResultVo.getData(); |
| | | } else { |
| | | throw new BusinessException(ResultCodes.RPC_DATA_TYPE_NOT_MATCH); |
| | | } |
| | | |
| | | } |
| | | |
| | | |
| | | protected void writeJSON(HttpServletRequest req, |
| | | HttpServletResponse resp, |
| | | ResultVO resultVO) throws IOException { |
| | | // 设置编码格式 |
| | | resp.setContentType("text/json;charset=utf-8"); |
| | | // 处理跨域问题 |
| | | resp.setHeader("Access-Control-Allow-Origin", "*"); |
| | | resp.setHeader("Access-Control-Allow-Methods", "POST, GET"); |
| | | |
| | | //输出JSON |
| | | PrintWriter out = resp.getWriter(); |
| | | out.write(JSONObject.toJSONString(resultVO)); |
| | | out.flush(); |
| | | out.close(); |
| | | } |
| | | } |