赞
踩
1、授权过滤,只要实现AuthConfigAdapter接口
2、利用Redis token超时时间,用户访问后台续时
@Component public class AuthFilter implements Filter { private static Logger logger = LoggerFactory.getLogger(AuthFilter.class); @Autowired private AuthConfigAdapter authConfigAdapter; @Autowired(required = false) private HttpHandler httpHandler; @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) request; HttpServletResponse resp = (HttpServletResponse) response; List<String> excludePathPatterns = authConfigAdapter.excludePathPatterns(); // 如果匹配不需要授权的路径,就不需要校验是否需要授权 if (CollectionUtil.isNotEmpty(excludePathPatterns)) { for (String excludePathPattern : excludePathPatterns) { AntPathMatcher pathMatcher = new AntPathMatcher(); if (pathMatcher.match(excludePathPattern, req.getRequestURI())) { chain.doFilter(req, resp); return; } } } String accessToken = req.getHeader("Authorization"); String sysType = req.getHeader("SysType"); if (StrUtil.isBlank(accessToken)) { logger.error("{} : {}", ResponseEnum.UNAUTHORIZED, req.getRequestURI()); httpHandler.printServerResponseToWeb(ServerResponseEntity.fail(ResponseEnum.UNAUTHORIZED)); return; } if(StrUtil.isBlank(sysType)){ logger.error("{} : {}", ResponseEnum.UNAUTHORIZED, req.getRequestURI()); httpHandler.printServerResponseToWeb(ServerResponseEntity.fail(ResponseEnum.UNAUTHORIZED)); return; } // 校验token,并返回用户信息 ServerResponseEntity<UserInfoInTokenBO> userInfoInTokenVoServerResponseEntity = TokenSecurity.checkToken(accessToken); if (!userInfoInTokenVoServerResponseEntity.isSuccess()) { logger.error("{} : {}", ServerResponseEntity.transform(userInfoInTokenVoServerResponseEntity), req.getRequestURI()); httpHandler.printServerResponseToWeb(ServerResponseEntity.transform(userInfoInTokenVoServerResponseEntity)); return; } if(userInfoInTokenVoServerResponseEntity.getData().getSysType() != Integer.parseInt(sysType)){ httpHandler.printServerResponseToWeb(ServerResponseEntity.fail(ResponseEnum.UNAUTHORIZED)); return; } AuthUserContext.set(BeanUtil.copyProperties(userInfoInTokenVoServerResponseEntity.getData(), UserInfoInTokenBO.class)); try { chain.doFilter(req, resp); } finally { AuthUserContext.clean(); } } } @Component @RefreshScope public class TokenSecurity { private static final Logger logger = LoggerFactory.getLogger(TokenSecurity.class); private static RedisTemplate<Object, Object> redisTemplate = null; private static StringRedisTemplate stringRedisTemplate; public TokenSecurity(RedisTemplate<Object, Object> redisTemplate, StringRedisTemplate stringRedisTemplate) { TokenSecurity.redisTemplate = redisTemplate; TokenSecurity.stringRedisTemplate = stringRedisTemplate; } public static ServerResponseEntity<UserInfoInTokenBO> checkToken(String accessToken) { ServerResponseEntity<UserInfoInTokenBO> userInfoByAccessTokenResponse = getUserInfoByAccessToken(accessToken, true); if (!userInfoByAccessTokenResponse.isSuccess()) { return ServerResponseEntity.transform(userInfoByAccessTokenResponse); } return ServerResponseEntity.success(userInfoByAccessTokenResponse.getData()); } public static ServerResponseEntity<UserInfoInTokenBO> getUserInfoByAccessToken(String accessToken, boolean needDecrypt) { if (StrUtil.isBlank(accessToken)) { return ServerResponseEntity.showFailMsg("accessToken is blank"); } String realAccessToken; if (needDecrypt) { ServerResponseEntity<String> decryptTokenEntity = decryptToken(accessToken); if (!decryptTokenEntity.isSuccess()) { return ServerResponseEntity.transform(decryptTokenEntity); } realAccessToken = decryptTokenEntity.getData(); } else { realAccessToken = accessToken; } UserInfoInTokenBO userInfoInTokenBO = (UserInfoInTokenBO) redisTemplate.opsForValue().get(getAccessKey(realAccessToken)); if (userInfoInTokenBO == null) { return ServerResponseEntity.fail(ResponseEnum.CLEAN_TOKEN); } String refreshToken = stringRedisTemplate.opsForValue().get(CacheNames.REFRESH_TO_ACCESS + userInfoInTokenBO.getMobile()); if (StrUtil.isBlank(refreshToken)) { return ServerResponseEntity.fail(ResponseEnum.CLEAN_TOKEN); } // 存在则token续时7200秒 redisTemplate.opsForValue().getAndExpire(getAccessKey(realAccessToken), 7200L, TimeUnit.SECONDS); return ServerResponseEntity.success(userInfoInTokenBO); } public static String getAccessKey(String accessToken) { return CacheNames.ACCESS + accessToken; } private static ServerResponseEntity<String> decryptToken(String data) { String decryptStr; String decryptToken; try { decryptStr = Base64.decodeStr(data); decryptToken = decryptStr.substring(0,32); // 创建token的时间,token使用时效性,防止攻击者通过一堆的尝试找到aes的密码,虽然aes是目前几乎最好的加密算法 long createTokenTime = Long.parseLong(decryptStr.substring(32,45)); // token的过期时间 int expiresIn = getExpiresIn(); long second = 1000L; if (System.currentTimeMillis() - createTokenTime > expiresIn * second) { return ServerResponseEntity.fail(ResponseEnum.TOKEN_ERROR); } } catch (Exception e) { logger.error(e.getMessage()); return ServerResponseEntity.fail(ResponseEnum.TOKEN_ERROR); } // 防止解密后的token是脚本,从而对redis进行攻击,uuid只能是数字和小写字母 if (!PrincipalUtil.isSimpleChar(decryptToken)) { return ServerResponseEntity.fail(ResponseEnum.TOKEN_ERROR); } return ServerResponseEntity.success(decryptToken); } private static int getExpiresIn() { // 3600秒 int expiresIn = 3600; expiresIn = expiresIn * 24; return expiresIn; } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。