|
|
@ -1,35 +1,24 @@ |
|
|
|
|
|
|
|
package com.epmet.filter; |
|
|
|
|
|
|
|
import com.alibaba.fastjson.JSON; |
|
|
|
import com.epmet.auth.ExternalAuthProcessor; |
|
|
|
import com.epmet.auth.InternalAuthProcessor; |
|
|
|
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.commons.tools.utils.Result; |
|
|
|
import com.epmet.jwt.JwtTokenUtils; |
|
|
|
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.GatewayFilter; |
|
|
|
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory; |
|
|
|
import org.springframework.core.io.buffer.DataBuffer; |
|
|
|
import org.springframework.http.HttpHeaders; |
|
|
|
import org.springframework.http.HttpStatus; |
|
|
|
import org.springframework.http.MediaType; |
|
|
|
import org.springframework.http.server.reactive.ServerHttpRequest; |
|
|
|
import org.springframework.stereotype.Component; |
|
|
|
import org.springframework.util.AntPathMatcher; |
|
|
|
import org.springframework.web.server.ServerWebExchange; |
|
|
|
import reactor.core.publisher.Flux; |
|
|
|
import reactor.core.publisher.Mono; |
|
|
|
|
|
|
|
import java.nio.charset.StandardCharsets; |
|
|
|
import java.util.Arrays; |
|
|
|
import java.util.List; |
|
|
|
|
|
|
@ -40,16 +29,25 @@ import java.util.List; |
|
|
|
* @since 1.0.0 |
|
|
|
*/ |
|
|
|
@Component("CpAuth") |
|
|
|
public class CpAuthGatewayFilterFactory extends AbstractGatewayFilterFactory<CpAuthGatewayFilterFactory.CpAuthConfig> implements UserTokenFilter { |
|
|
|
public class CpAuthGatewayFilterFactory extends AbstractGatewayFilterFactory<CpAuthGatewayFilterFactory.CpAuthConfig> { |
|
|
|
|
|
|
|
private Logger logger = LoggerFactory.getLogger(getClass()); |
|
|
|
@Autowired |
|
|
|
private CpProperty cpProperty; |
|
|
|
|
|
|
|
private final AntPathMatcher antPathMatcher = new AntPathMatcher(); |
|
|
|
|
|
|
|
public static final String AUTH_TYPE_INTERNAL = "internal"; |
|
|
|
public static final String AUTH_TYPE_EXTERNAL = "external"; |
|
|
|
public static final String AUTH_TYPE_NO_NEED = "no_need"; |
|
|
|
public static final String AUTH_TYPE_UNKNOW = "unknow"; |
|
|
|
|
|
|
|
@Autowired |
|
|
|
private JwtTokenUtils jwtTokenUtils; |
|
|
|
private CpProperty cpProperty; |
|
|
|
|
|
|
|
@Autowired |
|
|
|
private CpUserDetailRedis cpUserDetailRedis; |
|
|
|
private InternalAuthProcessor internalAuthProcessor; |
|
|
|
|
|
|
|
@Autowired |
|
|
|
private ExternalAuthProcessor externalAuthProcessor; |
|
|
|
|
|
|
|
@Override |
|
|
|
public List<String> shortcutFieldOrder() { |
|
|
@ -67,86 +65,77 @@ public class CpAuthGatewayFilterFactory extends AbstractGatewayFilterFactory<CpA |
|
|
|
return chain.filter(exchange); |
|
|
|
} |
|
|
|
|
|
|
|
//添加流水号
|
|
|
|
exchange.getRequest().mutate().header(AppClientConstant.TRANSACTION_SERIAL_KEY, new String[]{getTransactionSerial()}); |
|
|
|
|
|
|
|
ServerHttpRequest request = exchange.getRequest(); |
|
|
|
String requestUri = request.getPath().pathWithinApplication().value(); |
|
|
|
|
|
|
|
logger.info("CpAuthGatewayFilterFactory当前requestUri=[" + requestUri + "]CpAuthGatewayFilterFactory拦截成功"); |
|
|
|
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())); |
|
|
|
String authType = getAuthType(request); |
|
|
|
|
|
|
|
switch (authType) { |
|
|
|
case AUTH_TYPE_EXTERNAL: |
|
|
|
return externalAuthProcessor.auth(exchange, chain); |
|
|
|
case AUTH_TYPE_INTERNAL: |
|
|
|
return internalAuthProcessor.auth(exchange, chain); |
|
|
|
case AUTH_TYPE_UNKNOW: |
|
|
|
throw new RenException(EpmetErrorCode.ERR401.getCode(), "无法确定认证方式"); |
|
|
|
case AUTH_TYPE_NO_NEED: |
|
|
|
break; |
|
|
|
} |
|
|
|
}else{ |
|
|
|
baseTokenDto = null; |
|
|
|
|
|
|
|
return chain.filter(exchange); |
|
|
|
}; |
|
|
|
} |
|
|
|
|
|
|
|
String customerId = ""; |
|
|
|
/** |
|
|
|
* 判断需要执行的认证方式(内部应用认证还是外部应用认证) |
|
|
|
* @return |
|
|
|
*/ |
|
|
|
private String getAuthType(ServerHttpRequest request) { |
|
|
|
String requestUri = request.getPath().pathWithinApplication().value(); |
|
|
|
|
|
|
|
boolean existsInInternal = false; |
|
|
|
boolean existsInExternal = false; |
|
|
|
|
|
|
|
if (baseTokenDto != null) { |
|
|
|
if (AppClientConstant.APP_RESI.equals(baseTokenDto.getApp())) { |
|
|
|
// 居民端
|
|
|
|
TokenDto resiTokenDto = getLoginUserInfoByToken(token, jwtTokenUtils, cpUserDetailRedis, TokenDto.class); |
|
|
|
if (resiTokenDto != null) { |
|
|
|
customerId = resiTokenDto.getCustomerId(); |
|
|
|
baseTokenDto = resiTokenDto; |
|
|
|
} |
|
|
|
} else if (AppClientConstant.APP_GOV.equals(baseTokenDto.getApp())) { |
|
|
|
// 政府端
|
|
|
|
GovTokenDto govTokenDto = getLoginUserInfoByToken(token, jwtTokenUtils, cpUserDetailRedis, GovTokenDto.class); |
|
|
|
if (govTokenDto != null) { |
|
|
|
customerId = govTokenDto.getCustomerId(); |
|
|
|
baseTokenDto = govTokenDto; |
|
|
|
} |
|
|
|
} else if(AppClientConstant.APP_OPER.equals(baseTokenDto.getApp())){ |
|
|
|
//运营端
|
|
|
|
TokenDto resiTokenDto = getLoginUserInfoByToken(token, jwtTokenUtils, cpUserDetailRedis, TokenDto.class); |
|
|
|
if (resiTokenDto != null) { |
|
|
|
customerId = resiTokenDto.getCustomerId(); |
|
|
|
baseTokenDto = resiTokenDto; |
|
|
|
} |
|
|
|
for (String url : cpProperty.getInternalAuthUrls()) { |
|
|
|
if (antPathMatcher.match(url, requestUri)) { |
|
|
|
existsInInternal = true; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
//需要认证
|
|
|
|
if (needAuth(requestUri)) { |
|
|
|
if (StringUtils.isBlank(token)) { |
|
|
|
return response(exchange,new Result<>().error(EpmetErrorCode.ERR10005.getCode(),EpmetErrorCode.ERR10005.getMsg())); |
|
|
|
for (String url : cpProperty.getExternalAuthUrls()) { |
|
|
|
if (antPathMatcher.match(url, requestUri)) { |
|
|
|
existsInExternal = true; |
|
|
|
} |
|
|
|
// 校验token
|
|
|
|
try { |
|
|
|
validateTokenDto(baseTokenDto, token); |
|
|
|
} catch (RenException e) { |
|
|
|
return response(exchange,new Result<>().error(e.getCode(),e.getMsg())); |
|
|
|
} |
|
|
|
|
|
|
|
if (!existsInInternal && !existsInExternal) { |
|
|
|
// 既不再内部认证url,也不在外部认证url,那么不需要认证
|
|
|
|
return AUTH_TYPE_NO_NEED; |
|
|
|
} |
|
|
|
//添加流水号
|
|
|
|
exchange.getRequest().mutate().header(AppClientConstant.TRANSACTION_SERIAL_KEY, new String[]{getTransactionSerial()}); |
|
|
|
if (baseTokenDto != null) { |
|
|
|
String redisKey = baseTokenDto.getApp() + "-" + baseTokenDto.getClient() + "-" + baseTokenDto.getUserId(); |
|
|
|
logger.info("redisKey=" + redisKey); |
|
|
|
exchange.getRequest().mutate() |
|
|
|
.header(Constant.APP_USER_KEY, redisKey) |
|
|
|
.header(AppClientConstant.APP,baseTokenDto.getApp()) |
|
|
|
.header(AppClientConstant.CLIENT,baseTokenDto.getClient()) |
|
|
|
.header(AppClientConstant.USER_ID,baseTokenDto.getUserId()) |
|
|
|
; |
|
|
|
if (StringUtils.equals(baseTokenDto.getApp(), "gov")) {//工作端
|
|
|
|
if(StringUtils.isNotBlank(customerId)){ |
|
|
|
exchange.getRequest().mutate().header(AppClientConstant.CUSTOMER_ID, customerId); |
|
|
|
|
|
|
|
// 内部认证
|
|
|
|
if (StringUtils.isNotBlank(getHeader(request, Constant.AUTHORIZATION_HEADER)) |
|
|
|
&& existsInInternal) { |
|
|
|
return AUTH_TYPE_INTERNAL; |
|
|
|
} |
|
|
|
} else if (StringUtils.equals(baseTokenDto.getApp(), "public")) {//公众号端
|
|
|
|
exchange.getRequest().mutate().header(AppClientConstant.CUSTOMER_ID, customerId); |
|
|
|
|
|
|
|
if (StringUtils.isNotBlank(getHeader(request, Constant.ACCESS_TOKEN_HEADER)) |
|
|
|
&& existsInExternal) { |
|
|
|
return AUTH_TYPE_EXTERNAL; |
|
|
|
} |
|
|
|
ServerHttpRequest build = exchange.getRequest().mutate().build(); |
|
|
|
return chain.filter(exchange.mutate().request(build).build()); |
|
|
|
|
|
|
|
return AUTH_TYPE_UNKNOW; |
|
|
|
} |
|
|
|
|
|
|
|
return chain.filter(exchange); |
|
|
|
}; |
|
|
|
/** |
|
|
|
* 获取请求头 |
|
|
|
* @param request |
|
|
|
* @return |
|
|
|
*/ |
|
|
|
private String getHeader(ServerHttpRequest request, String headerName) { |
|
|
|
HttpHeaders headers = request.getHeaders(); |
|
|
|
return headers.getFirst(headerName); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
@ -166,71 +155,6 @@ public class CpAuthGatewayFilterFactory extends AbstractGatewayFilterFactory<CpA |
|
|
|
return sb.toString(); |
|
|
|
} |
|
|
|
|
|
|
|
//public TokenDto getLoginUserInfo(String token) {
|
|
|
|
// //是否过期
|
|
|
|
// Claims claims = jwtTokenUtils.getClaimByToken(token);
|
|
|
|
// if (claims == null || jwtTokenUtils.isTokenExpired(claims.getExpiration())) {
|
|
|
|
// throw new RenException(ErrorCode.ERR401.getCode(),ErrorCode.ERR401.getMsg());
|
|
|
|
// }
|
|
|
|
// //获取用户ID
|
|
|
|
// String app = (String) claims.get("app");
|
|
|
|
// String client = (String) claims.get("client");
|
|
|
|
// String userId = (String) claims.get("userId");
|
|
|
|
// //查询Redis
|
|
|
|
// TokenDto tokenDto = cpUserDetailRedis.get(app, client, userId);
|
|
|
|
// if (null == tokenDto) {
|
|
|
|
// //说明登录状态时效(超时)
|
|
|
|
// throw new RenException(ErrorCode.ERR10006.getCode(),ErrorCode.ERR10006.getMsg());
|
|
|
|
// }else{
|
|
|
|
// //Redis中存在数据,取出token,进行比对
|
|
|
|
// if(StringUtils.equals(tokenDto.getToken(),token)){
|
|
|
|
// //用户携带token与Redis中一致
|
|
|
|
//
|
|
|
|
// }else{
|
|
|
|
// //用户携带token与Redis中不一致,说明当前用户此次会话失效,提示重新登陆
|
|
|
|
// throw new RenException(ErrorCode.ERR10007.getCode(),ErrorCode.ERR10007.getMsg());
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// return tokenDto;
|
|
|
|
//}
|
|
|
|
|
|
|
|
private Mono<Void> response(ServerWebExchange exchange, Object object) { |
|
|
|
String json = JSON.toJSONString(object); |
|
|
|
DataBuffer buffer = exchange.getResponse().bufferFactory().wrap(json.getBytes(StandardCharsets.UTF_8)); |
|
|
|
exchange.getResponse().getHeaders().setContentType(MediaType.APPLICATION_JSON_UTF8); |
|
|
|
exchange.getResponse().setStatusCode(HttpStatus.OK); |
|
|
|
return exchange.getResponse().writeWith(Flux.just(buffer)); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 是否需要认证 |
|
|
|
* @param requestUri |
|
|
|
* @return |
|
|
|
*/ |
|
|
|
private boolean needAuth(String requestUri) { |
|
|
|
// 优先判断白名单,在白名单中的就直接放行
|
|
|
|
for (String url : cpProperty.getUrlWhiteList()) { |
|
|
|
if (antPathMatcher.match(url, requestUri)) { |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
for (String url : cpProperty.getSwaggerUrls()) { |
|
|
|
if (antPathMatcher.match(url, requestUri)) { |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
for (String url : cpProperty.getUrls()) { |
|
|
|
if (antPathMatcher.match(url, requestUri)) { |
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
public static class CpAuthConfig { |
|
|
|
|
|
|
|
/** |
|
|
@ -250,45 +174,4 @@ public class CpAuthGatewayFilterFactory extends AbstractGatewayFilterFactory<CpA |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 校验Token是否异常 |
|
|
|
* @param tokenDto |
|
|
|
* @param tokenStr |
|
|
|
*/ |
|
|
|
public 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()); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 从请求中获取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); |
|
|
|
logger.info("token=" + token); |
|
|
|
} else { |
|
|
|
logger.info("authorization=" + token); |
|
|
|
} |
|
|
|
if (StringUtils.isBlank(token)) { |
|
|
|
token = request.getQueryParams().getFirst(Constant.AUTHORIZATION_HEADER); |
|
|
|
logger.info("params token:" + token); |
|
|
|
} |
|
|
|
return token; |
|
|
|
} |
|
|
|
} |
|
|
|