package com.epmet.auth; import com.epmet.commons.tools.constant.AppClientConstant; import com.epmet.commons.tools.constant.Constant; import com.epmet.commons.tools.exception.EpmetErrorCode; import com.epmet.commons.tools.exception.RenException; import com.epmet.commons.tools.security.dto.BaseTokenDto; import com.epmet.commons.tools.utils.CpUserDetailRedis; import com.epmet.filter.CpProperty; import com.epmet.jwt.JwtTokenUtils; import io.jsonwebtoken.Claims; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.gateway.filter.GatewayFilterChain; import org.springframework.http.HttpHeaders; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.stereotype.Component; import org.springframework.util.AntPathMatcher; import org.springframework.web.server.ServerWebExchange; import java.util.Date; /** * 内部认证处理器 */ @Component public class InternalAuthProcessor extends AuthProcessor { private Logger logger = LoggerFactory.getLogger(getClass()); @Autowired private JwtTokenUtils jwtTokenUtils; @Autowired private CpUserDetailRedis cpUserDetailRedis; private final AntPathMatcher antPathMatcher = new AntPathMatcher(); @Autowired private CpProperty cpProperty; @Override public ServerWebExchange auth(ServerWebExchange exchange, GatewayFilterChain chain) { ServerHttpRequest request = exchange.getRequest(); String requestUri = request.getPath().pathWithinApplication().value(); String token = getTokenFromRequest(request); boolean needAuth = needAuth(requestUri); if (needAuth && StringUtils.isBlank(token)) { // token不能为空 throw new RenException(EpmetErrorCode.ERR10005.getCode(), EpmetErrorCode.ERR10005.getMsg()); } BaseTokenDto baseTokenDto = null; String app = ""; String client = ""; String userId = ""; String customerId = ""; Date expiration = null; if(StringUtils.isNotBlank(token)){ //是否过期 Claims claims = jwtTokenUtils.getClaimByToken(token); if (claims != null) { app = (String) claims.get(AppClientConstant.APP); client = (String) claims.get(AppClientConstant.CLIENT); userId = (String) claims.get(AppClientConstant.USER_ID); expiration = claims.getExpiration(); baseTokenDto = cpUserDetailRedis.get(app, client, userId, BaseTokenDto.class); } } if (baseTokenDto != null) { customerId = baseTokenDto.getCustomerId(); } if (needAuth) { validateToken(baseTokenDto, token, expiration); } // 添加header ServerHttpRequest.Builder builder = exchange.getRequest().mutate(); if (StringUtils.isNotBlank(app)) { builder.header(AppClientConstant.APP, app); } if (StringUtils.isNotBlank(client)) { builder.header(AppClientConstant.CLIENT, client); } if (StringUtils.isNotBlank(userId)) { builder.header(AppClientConstant.USER_ID, userId); } if (baseTokenDto != null) { String redisKey = baseTokenDto.getApp() + "-" + baseTokenDto.getClient() + "-" + baseTokenDto.getUserId(); logger.info("redisKey=" + redisKey); builder.header(Constant.APP_USER_KEY, redisKey); } if(StringUtils.isNotBlank(customerId)){ builder.header(AppClientConstant.CUSTOMER_ID, customerId); } ServerHttpRequest shr = builder.build(); return exchange.mutate().request(shr).build(); } /** * 是否需要认证 * @param requestUri * @return */ private boolean needAuth(String requestUri) { for (String url : cpProperty.getInternalAuthUrlsWhiteList()) { if (antPathMatcher.match(url, requestUri)) { return false; } } for (String url : cpProperty.getInternalAuthUrls()) { if (antPathMatcher.match(url, requestUri)) { return true; } } return false; } /** * 从请求中获取token * @param request * @return */ private String getTokenFromRequest(ServerHttpRequest request) { HttpHeaders headers = request.getHeaders(); String token = headers.getFirst(Constant.AUTHORIZATION_HEADER); if (StringUtils.isBlank(token)) { token = headers.getFirst(Constant.TOKEN_HEADER); } if (StringUtils.isBlank(token)) { token = request.getQueryParams().getFirst(Constant.AUTHORIZATION_HEADER); } return token; } /** * @Description 从用户token中取app,client,userId三项数据 * @return * @author wxz * @date 2021.06.11 15:04 */ private BaseTokenDto getBaseTokenDto(String token, JwtTokenUtils jwtTokenUtils) { //是否过期 Claims claims = jwtTokenUtils.getClaimByToken(token); if (claims == null || jwtTokenUtils.isTokenExpired(claims.getExpiration())) { return null; } //获取用户ID String app = (String) claims.get("app"); String client = (String) claims.get("client"); String userId = (String) claims.get("userId"); return new BaseTokenDto(app, client, userId, token); } /** * 校验Token是否异常 * @param tokenDto * @param tokenStr */ private void validateToken(BaseTokenDto tokenDto, String tokenStr, Date expiration) { if (null == tokenDto || jwtTokenUtils.isTokenExpired(expiration)) { //说明登录状态时效(超时) throw new RenException(EpmetErrorCode.ERR10006.getCode(), EpmetErrorCode.ERR10006.getMsg()); }else{ //Redis中存在数据,取出token,进行比对 if(!StringUtils.equals(tokenDto.getToken(),tokenStr)){ //用户携带token与Redis中不一致,说明当前用户此次会话失效,提示重新登陆 throw new RenException(EpmetErrorCode.ERR10007.getCode(), EpmetErrorCode.ERR10007.getMsg()); } } } }