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.security.dto.GovTokenDto; import com.epmet.commons.tools.security.dto.TokenDto; 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; /** * 内部认证处理器 */ @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); //BaseTokenDto baseTokenDto = StringUtils.isNotBlank(token) ? getBaseTokenDto(token, jwtTokenUtils) : null; BaseTokenDto baseTokenDto; if(StringUtils.isNotBlank(token)){ try{ baseTokenDto = getBaseTokenDto(token, jwtTokenUtils); }catch(RenException e){ //return response(exchange,new Result<>().error(e.getCode(),e.getMsg())); throw new RenException(e.getCode(), e.getInternalMsg()); } }else{ baseTokenDto = null; } String customerId = ""; if (baseTokenDto != null) { if (AppClientConstant.APP_RESI.equals(baseTokenDto.getApp())) { // 居民端 TokenDto resiTokenDto = getLoginUserInfoByToken(token, jwtTokenUtils, TokenDto.class); if (resiTokenDto != null) { customerId = resiTokenDto.getCustomerId(); baseTokenDto = resiTokenDto; } } else if (AppClientConstant.APP_GOV.equals(baseTokenDto.getApp())) { // 政府端 GovTokenDto govTokenDto = getLoginUserInfoByToken(token, jwtTokenUtils, GovTokenDto.class); if (govTokenDto != null) { customerId = govTokenDto.getCustomerId(); baseTokenDto = govTokenDto; } } else if(AppClientConstant.APP_OPER.equals(baseTokenDto.getApp())){ //运营端 TokenDto resiTokenDto = getLoginUserInfoByToken(token, jwtTokenUtils, TokenDto.class); if (resiTokenDto != null) { customerId = resiTokenDto.getCustomerId(); baseTokenDto = resiTokenDto; } } } if (needAuth(requestUri)) { // 校验token if (StringUtils.isBlank(token)) { //return response(exchange, new Result<>().error(EpmetErrorCode.ERR10005.getCode(), EpmetErrorCode.ERR10005.getMsg())); throw new RenException(EpmetErrorCode.ERR10005.getCode(), EpmetErrorCode.ERR10005.getMsg()); } try { validateTokenDto(baseTokenDto, token); } catch (RenException e) { //return response(exchange, new Result<>().error(e.getCode(), e.getMsg())); throw new RenException(e.getCode(), e.getInternalMsg()); } } // 添加header if (baseTokenDto != null) { String redisKey = baseTokenDto.getApp() + "-" + baseTokenDto.getClient() + "-" + baseTokenDto.getUserId(); logger.info("redisKey=" + redisKey); ServerHttpRequest.Builder builder = exchange.getRequest().mutate(); builder.header(Constant.APP_USER_KEY, redisKey); builder.header(AppClientConstant.APP,baseTokenDto.getApp()); builder.header(AppClientConstant.CLIENT,baseTokenDto.getClient()); builder.header(AppClientConstant.USER_ID,baseTokenDto.getUserId()); if (StringUtils.isNotBlank(baseTokenDto.getCustomerId())) { builder.header(AppClientConstant.CUSTOMER_ID,baseTokenDto.getCustomerId()); } if (StringUtils.equals(baseTokenDto.getApp(), "gov")) {//工作端 if(StringUtils.isNotBlank(customerId)){ exchange.getRequest().mutate().header(AppClientConstant.CUSTOMER_ID, customerId); } } else if (StringUtils.equals(baseTokenDto.getApp(), "public")) {//公众号端 exchange.getRequest().mutate().header(AppClientConstant.CUSTOMER_ID, customerId); } ServerHttpRequest build = exchange.getRequest().mutate().build(); return exchange.mutate().request(build).build(); } return exchange; } /** * 是否需要认证 * @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; } 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); } private T getLoginUserInfoByToken(String token, JwtTokenUtils jwtTokenUtils, Class clz) { BaseTokenDto baseTokenDto = getBaseTokenDto(token, jwtTokenUtils); //查询Redis return cpUserDetailRedis.get(baseTokenDto.getApp(), baseTokenDto.getClient(), baseTokenDto.getUserId(), clz); } /** * 校验Token是否异常 * @param tokenDto * @param tokenStr */ private void validateTokenDto(BaseTokenDto tokenDto, String tokenStr) { if (null == tokenDto) { //说明登录状态时效(超时) throw new RenException(EpmetErrorCode.ERR10006.getCode()); }else{ //Redis中存在数据,取出token,进行比对 if(StringUtils.equals(tokenDto.getToken(),tokenStr)){ //用户携带token与Redis中一致 }else{ //用户携带token与Redis中不一致,说明当前用户此次会话失效,提示重新登陆 throw new RenException(EpmetErrorCode.ERR10007.getCode()); } } } }