diff --git a/epmet-commons/epmet-commons-tools/src/main/java/com/epmet/commons/tools/constant/Constant.java b/epmet-commons/epmet-commons-tools/src/main/java/com/epmet/commons/tools/constant/Constant.java
index 67aced6dbe..3636e2942d 100644
--- a/epmet-commons/epmet-commons-tools/src/main/java/com/epmet/commons/tools/constant/Constant.java
+++ b/epmet-commons/epmet-commons-tools/src/main/java/com/epmet/commons/tools/constant/Constant.java
@@ -96,6 +96,8 @@ public interface Constant {
* authorization header
*/
String AUTHORIZATION_HEADER = "authorization";
+
+ String ACCESS_TOKEN_HEADER = "AccessToken";
/**
* APP用户标识
*/
diff --git a/epmet-gateway/pom.xml b/epmet-gateway/pom.xml
index 78fa471715..ed64b82243 100644
--- a/epmet-gateway/pom.xml
+++ b/epmet-gateway/pom.xml
@@ -58,6 +58,13 @@
2.0.0
compile
+
+
+
+ com.epmet
+ common-service-client
+ 2.0.0
+
diff --git a/epmet-gateway/src/main/java/com/epmet/auth/AuthProcessor.java b/epmet-gateway/src/main/java/com/epmet/auth/AuthProcessor.java
new file mode 100644
index 0000000000..4ef47a2eae
--- /dev/null
+++ b/epmet-gateway/src/main/java/com/epmet/auth/AuthProcessor.java
@@ -0,0 +1,26 @@
+package com.epmet.auth;
+
+import com.alibaba.fastjson.JSON;
+import org.springframework.cloud.gateway.filter.GatewayFilterChain;
+import org.springframework.core.io.buffer.DataBuffer;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+import org.springframework.web.server.ServerWebExchange;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+
+import java.nio.charset.StandardCharsets;
+
+public abstract class AuthProcessor {
+
+ abstract Mono auth(ServerWebExchange exchange, GatewayFilterChain chain);
+
+ protected Mono 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));
+ }
+
+}
diff --git a/epmet-gateway/src/main/java/com/epmet/auth/ExtAppAuthProcessor.java b/epmet-gateway/src/main/java/com/epmet/auth/ExtAppAuthProcessor.java
new file mode 100644
index 0000000000..4dc7a22c71
--- /dev/null
+++ b/epmet-gateway/src/main/java/com/epmet/auth/ExtAppAuthProcessor.java
@@ -0,0 +1,30 @@
+package com.epmet.auth;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * 外部应用认证处理器父类
+ */
+public abstract class ExtAppAuthProcessor {
+
+ private Logger logger = LoggerFactory.getLogger(getClass());
+
+ private int diffMillins = 1000 * 60 * 5;
+
+ public abstract void auth(String appId, String token, Long ts);
+
+ /**
+ * 时间戳校验
+ * @param timestamp
+ * @return
+ */
+ protected boolean validTimeStamp(Long timestamp) {
+ long now = System.currentTimeMillis();
+ if (Math.abs(now - timestamp) > diffMillins) {
+ return false;
+ }
+ return true;
+ }
+}
diff --git a/epmet-gateway/src/main/java/com/epmet/auth/ExtAppJwtAuthProcessor.java b/epmet-gateway/src/main/java/com/epmet/auth/ExtAppJwtAuthProcessor.java
new file mode 100644
index 0000000000..431907cde5
--- /dev/null
+++ b/epmet-gateway/src/main/java/com/epmet/auth/ExtAppJwtAuthProcessor.java
@@ -0,0 +1,88 @@
+package com.epmet.auth;
+
+import com.epmet.commons.tools.exception.EpmetErrorCode;
+import com.epmet.commons.tools.exception.ExceptionUtils;
+import com.epmet.commons.tools.exception.RenException;
+import com.epmet.commons.tools.redis.RedisKeys;
+import com.epmet.commons.tools.redis.RedisUtils;
+import com.epmet.commons.tools.utils.Result;
+import com.epmet.commons.tools.utils.SpringContextUtils;
+import com.epmet.feign.EpmetCommonServiceOpenFeignClient;
+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.stereotype.Component;
+
+/**
+ * jwt 认证处理器
+ */
+@Component
+public class ExtAppJwtAuthProcessor extends ExtAppAuthProcessor {
+
+ private static Logger logger = LoggerFactory.getLogger(ExtAppJwtAuthProcessor.class);
+
+ @Autowired
+ private JwtTokenUtils jwtTokenUtils;
+
+ @Autowired
+ private RedisUtils redisUtils;
+
+ @Override
+ public void auth(String appId, String token, Long ts) {
+ String secret;
+ if (StringUtils.isBlank(secret = getTokenFromCache(appId))) {
+ throw new RenException(EpmetErrorCode.OPER_EXTERNAL_APP_AUTH_ERROR.getCode(), String.format("根据AppId:【%s】没有找到对应的秘钥", appId));
+ }
+
+ Claims claim;
+ try {
+ claim = jwtTokenUtils.getClaimByToken(token, secret);
+ } catch (Exception e) {
+ String errorStackTrace = ExceptionUtils.getErrorStackTrace(e);
+ logger.error("解析token失败:{}", errorStackTrace);
+ throw new RenException(EpmetErrorCode.OPER_EXTERNAL_APP_AUTH_ERROR.getCode(), "解析token失败");
+ }
+
+ String appIdIn = (String)claim.get("appId");
+ String customerId = (String)claim.get("customerId");
+ Long timestamp = (Long)claim.get("ts");
+
+ //校验时间戳,允许5分钟误差
+ if (StringUtils.isAnyBlank(appIdIn, customerId) || timestamp == null) {
+ logger.error("access token不完整。{},{},{}", appIdIn, customerId, timestamp);
+ throw new RenException(EpmetErrorCode.OPER_EXTERNAL_APP_AUTH_ERROR.getCode(), "AccessToken不完整");
+ }
+
+ if (!validTimeStamp(timestamp)) {
+ logger.error("extapp token已经超时,请求被拒绝");
+ throw new RenException(EpmetErrorCode.OPER_EXTERNAL_APP_AUTH_ERROR.getCode(), "AccessToken已经超时");
+ }
+
+ if (!appId.equals(appIdIn)) {
+ logger.error("AppId不对应,token外部的:{}, token内部解析出来的:{}", appId, appIdIn);
+ throw new RenException(EpmetErrorCode.OPER_EXTERNAL_APP_AUTH_ERROR.getCode(), "AppId不匹配");
+ }
+ }
+
+ /**
+ * 通过APP ID查询对应的秘钥
+ * @param appId
+ * @return
+ */
+ public String getTokenFromCache(String appId) {
+ String secret = (String)redisUtils.get(RedisKeys.getExternalAppSecretKey(appId));
+ if (StringUtils.isBlank(secret)) {
+ EpmetCommonServiceOpenFeignClient commonService = SpringContextUtils.getBean(EpmetCommonServiceOpenFeignClient.class);
+ Result result = commonService.getSecret(appId);
+ if (!result.success()) {
+ throw new RenException(EpmetErrorCode.OPER_EXTERNAL_APP_AUTH_ERROR.getCode(), result.getInternalMsg());
+ }
+ secret = result.getData();
+ redisUtils.set(RedisKeys.getExternalAppSecretKey(appId), secret);
+ }
+ return secret;
+ }
+}
diff --git a/epmet-gateway/src/main/java/com/epmet/auth/ExtAppMD5AuthProcessor.java b/epmet-gateway/src/main/java/com/epmet/auth/ExtAppMD5AuthProcessor.java
new file mode 100644
index 0000000000..c1869cb1ab
--- /dev/null
+++ b/epmet-gateway/src/main/java/com/epmet/auth/ExtAppMD5AuthProcessor.java
@@ -0,0 +1,74 @@
+package com.epmet.auth;
+
+import com.epmet.commons.tools.exception.EpmetErrorCode;
+import com.epmet.commons.tools.exception.RenException;
+import com.epmet.commons.tools.redis.RedisKeys;
+import com.epmet.commons.tools.redis.RedisUtils;
+import com.epmet.commons.tools.utils.Md5Util;
+import com.epmet.commons.tools.utils.Result;
+import com.epmet.commons.tools.utils.SpringContextUtils;
+import com.epmet.feign.EpmetCommonServiceOpenFeignClient;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+/**
+ * md5 认证处理器
+ */
+@Component
+public class ExtAppMD5AuthProcessor extends ExtAppAuthProcessor {
+
+ private static Logger logger = LoggerFactory.getLogger(ExtAppMD5AuthProcessor.class);
+
+ //@Autowired
+ //private EpmetCommonServiceOpenFeignClient commonServiceOpenFeignClient;
+
+ @Autowired
+ private RedisUtils redisUtils;
+
+ @Override
+ public void auth(String appId, String token, Long ts) {
+ if (ts == null) {
+ throw new RenException(EpmetErrorCode.OPER_EXTERNAL_APP_AUTH_ERROR.getCode(), "需要传入时间戳参数");
+ }
+ String secret;
+ if (StringUtils.isBlank(secret = getTokenFromCache(appId))) {
+ throw new RenException(EpmetErrorCode.OPER_EXTERNAL_APP_AUTH_ERROR.getCode(), String.format("根据AppId:%s没有找到对应的秘钥", appId));
+ }
+
+ String localDigest = Md5Util.md5(secret.concat(":") + ts);
+ if (!localDigest.equals(token)) {
+ // 调用方生成的摘要跟本地生成的摘要不匹配
+ throw new RenException(EpmetErrorCode.OPER_EXTERNAL_APP_AUTH_ERROR.getCode(), "签名不匹配,认证失败");
+ }
+
+ if (!validTimeStamp(ts)) {
+ logger.error("AccessToken已经超时,请求被拒绝");
+ throw new RenException(EpmetErrorCode.OPER_EXTERNAL_APP_AUTH_ERROR.getCode(), "AccessToken已经超时,请求被拒绝");
+ }
+ }
+
+ /**
+ * 通过APP ID查询对应的秘钥
+ *
+ * @param appId
+ * @return
+ */
+ public String getTokenFromCache(String appId) {
+ String secret = (String) redisUtils.get(RedisKeys.getExternalAppSecretKey(appId));
+ if (StringUtils.isBlank(secret)) {
+ EpmetCommonServiceOpenFeignClient commonService = SpringContextUtils.getBean(EpmetCommonServiceOpenFeignClient.class);
+ Result result = commonService.getSecret(appId);
+ if (!result.success()) {
+ throw new RenException(EpmetErrorCode.OPER_EXTERNAL_APP_AUTH_ERROR.getCode(), result.getInternalMsg());
+ }
+
+ secret = result.getData();
+ redisUtils.set(RedisKeys.getExternalAppSecretKey(appId), secret);
+ }
+ return secret;
+ }
+
+}
diff --git a/epmet-gateway/src/main/java/com/epmet/auth/ExternalAuthProcessor.java b/epmet-gateway/src/main/java/com/epmet/auth/ExternalAuthProcessor.java
new file mode 100644
index 0000000000..7b46e870ce
--- /dev/null
+++ b/epmet-gateway/src/main/java/com/epmet/auth/ExternalAuthProcessor.java
@@ -0,0 +1,79 @@
+package com.epmet.auth;
+
+import com.epmet.commons.tools.exception.EpmetErrorCode;
+import com.epmet.commons.tools.exception.ExceptionUtils;
+import com.epmet.commons.tools.exception.RenException;
+import com.epmet.commons.tools.utils.Result;
+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.stereotype.Component;
+import org.springframework.web.server.ServerWebExchange;
+import reactor.core.publisher.Mono;
+
+/**
+ * 外部应用认证
+ */
+@Component
+public class ExternalAuthProcessor extends AuthProcessor {
+
+ private Logger logger = LoggerFactory.getLogger(getClass());
+
+ // 头s
+ public static final String AUTHORIZATION_TOKEN_HEADER_KEY = "Authorization";
+ public static final String ACCESS_TOKEN_HEADER_KEY = "AccessToken";
+ public static final String APP_ID_HEADER_KEY = "appId";
+ public static final String APP_ID_TIMESTAMP_KEY = "ts";
+ public static final String APP_ID_CUSTOMER_ID_KEY = "CustomerId";
+ public static final String APP_ID_AUTY_TYPE_KEY = "AuthType";
+
+ // 认证方式
+ public static final String APP_AUTH_TYPE_JWT = "jwt";
+ public static final String APP_AUTH_TYPE_MD5 = "md5";
+
+
+ @Autowired
+ private ExtAppJwtAuthProcessor jwtAuthProcessor;
+
+ @Autowired
+ private ExtAppMD5AuthProcessor md5AuthProcessor;
+
+ @Override
+ public Mono auth(ServerWebExchange exchange, GatewayFilterChain chain) {
+ HttpHeaders headers = exchange.getRequest().getHeaders();
+
+ String token = headers.getFirst(ACCESS_TOKEN_HEADER_KEY);
+ String appId = headers.getFirst(APP_ID_HEADER_KEY);
+ String ts = headers.getFirst(APP_ID_TIMESTAMP_KEY);
+ String customerId = headers.getFirst(APP_ID_CUSTOMER_ID_KEY);
+ String authType = headers.getFirst(APP_ID_AUTY_TYPE_KEY);
+
+ if (StringUtils.isAnyBlank(token, appId)) {
+ throw new RenException("请求头中的AccessToken和AppId不能为空");
+ }
+
+ logger.info("外部应用请求认证拦截Aspect执行,appId:{}, token:{}, ts:{}, customerId:{}, authType:{}",
+ appId, token, ts, customerId, authType);
+
+ // 没传authType或者传的jwt都用jwtprocessor处理
+ try {
+ if (StringUtils.isBlank(authType) || APP_AUTH_TYPE_JWT.equals(authType)) {
+ jwtAuthProcessor.auth(appId, token, StringUtils.isNotBlank(ts) ? new Long(ts) : null);
+ } else if (APP_AUTH_TYPE_MD5.equals(authType)) {
+ md5AuthProcessor.auth(appId, token, StringUtils.isNotBlank(ts) ? new Long(ts) : null);
+ } else {
+ throw new RenException(EpmetErrorCode.OPER_EXTERNAL_APP_AUTH_ERROR.getCode(), "未知的认证类型");
+ }
+ } catch (RenException e) {
+ return response(exchange, new Result<>().error(e.getCode(), e.getMsg()));
+ } catch (Exception e) {
+ logger.error("外部应用请求认证发生未知错误:" + ExceptionUtils.getErrorStackTrace(e));
+ return response(exchange, new Result<>().error("外部应用请求认证发生未知错误"));
+ }
+
+ return chain.filter(exchange);
+ }
+}
diff --git a/epmet-gateway/src/main/java/com/epmet/auth/InternalAuthProcessor.java b/epmet-gateway/src/main/java/com/epmet/auth/InternalAuthProcessor.java
new file mode 100644
index 0000000000..ee247c843b
--- /dev/null
+++ b/epmet-gateway/src/main/java/com/epmet/auth/InternalAuthProcessor.java
@@ -0,0 +1,175 @@
+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.commons.tools.utils.Result;
+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.web.server.ServerWebExchange;
+import reactor.core.publisher.Mono;
+
+/**
+ * 内部认证处理器
+ */
+@Component
+public class InternalAuthProcessor extends AuthProcessor {
+
+ private Logger logger = LoggerFactory.getLogger(getClass());
+
+ @Autowired
+ private JwtTokenUtils jwtTokenUtils;
+
+ @Autowired
+ private CpUserDetailRedis cpUserDetailRedis;
+
+ @Override
+ public Mono auth(ServerWebExchange exchange, GatewayFilterChain chain) {
+ 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()));
+ }
+ }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;
+ }
+ }
+ }
+
+ // 校验token
+ if (StringUtils.isBlank(token)) {
+ return response(exchange,new Result<>().error(EpmetErrorCode.ERR10005.getCode(),EpmetErrorCode.ERR10005.getMsg()));
+ }
+ try {
+ validateTokenDto(baseTokenDto, token);
+ } catch (RenException e) {
+ return response(exchange,new Result<>().error(e.getCode(),e.getMsg()));
+ }
+
+ // 添加header
+ 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);
+ }
+ } else if (StringUtils.equals(baseTokenDto.getApp(), "public")) {//公众号端
+ exchange.getRequest().mutate().header(AppClientConstant.CUSTOMER_ID, customerId);
+ }
+ ServerHttpRequest build = exchange.getRequest().mutate().build();
+ return chain.filter(exchange.mutate().request(build).build());
+ }
+
+ return chain.filter(exchange);
+ }
+
+ /**
+ * 从请求中获取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());
+ }
+ }
+ }
+}
diff --git a/epmet-gateway/src/main/java/com/epmet/filter/CpAuthGatewayFilterFactory.java b/epmet-gateway/src/main/java/com/epmet/filter/CpAuthGatewayFilterFactory.java
index 7c74fa6763..59f52483b2 100644
--- a/epmet-gateway/src/main/java/com/epmet/filter/CpAuthGatewayFilterFactory.java
+++ b/epmet-gateway/src/main/java/com/epmet/filter/CpAuthGatewayFilterFactory.java
@@ -2,16 +2,12 @@
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;
@@ -40,16 +36,25 @@ import java.util.List;
* @since 1.0.0
*/
@Component("CpAuth")
-public class CpAuthGatewayFilterFactory extends AbstractGatewayFilterFactory implements UserTokenFilter {
+public class CpAuthGatewayFilterFactory extends AbstractGatewayFilterFactory {
+
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 shortcutFieldOrder() {
@@ -67,82 +72,23 @@ public class CpAuthGatewayFilterFactory extends AbstractGatewayFilterFactory().error(e.getCode(),e.getMsg()));
- }
- }else{
- baseTokenDto = null;
- }
-
- String customerId = "";
-
- 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;
- }
- }
- }
-
- //需要认证
- if (needAuth(requestUri)) {
- if (StringUtils.isBlank(token)) {
- return response(exchange,new Result<>().error(EpmetErrorCode.ERR10005.getCode(),EpmetErrorCode.ERR10005.getMsg()));
- }
- // 校验token
- try {
- validateTokenDto(baseTokenDto, token);
- } catch (RenException e) {
- return response(exchange,new Result<>().error(e.getCode(),e.getMsg()));
- }
- }
//添加流水号
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);
- }
- } else if (StringUtils.equals(baseTokenDto.getApp(), "public")) {//公众号端
- exchange.getRequest().mutate().header(AppClientConstant.CUSTOMER_ID, customerId);
- }
- ServerHttpRequest build = exchange.getRequest().mutate().build();
- return chain.filter(exchange.mutate().request(build).build());
+
+ ServerHttpRequest request = exchange.getRequest();
+
+ 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_NO_NEED:
+ break;
+ default:
+ return response(exchange, new Result<>().error(EpmetErrorCode.ERR401.getCode(),
+ EpmetErrorCode.ERR401.getMsg()));
}
return chain.filter(exchange);
@@ -150,85 +96,71 @@ public class CpAuthGatewayFilterFactory extends AbstractGatewayFilterFactory 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 request
+ * @return
+ */
+ private String getHeader(ServerHttpRequest request, String headerName) {
+ HttpHeaders headers = request.getHeaders();
+ return headers.getFirst(headerName);
}
/**
- * 是否需要认证
- * @param requestUri
+ * 获取事务流水号
* @return
*/
- private boolean needAuth(String requestUri) {
- // 优先判断白名单,在白名单中的就直接放行
- for (String url : cpProperty.getUrlWhiteList()) {
- if (antPathMatcher.match(url, requestUri)) {
- return false;
- }
- }
+ public static String getTransactionSerial() {
+ String[] letterPool = {"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n"
+ , "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"};
- for (String url : cpProperty.getSwaggerUrls()) {
- if (antPathMatcher.match(url, requestUri)) {
- return false;
- }
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < 2; i++) {
+ sb.append(letterPool[(int) (Math.random() * 25)]);
}
- for (String url : cpProperty.getUrls()) {
- if (antPathMatcher.match(url, requestUri)) {
- return true;
- }
- }
- return false;
+ sb.append(System.currentTimeMillis());
+ return sb.toString();
}
public static class CpAuthConfig {
@@ -250,45 +182,12 @@ public class CpAuthGatewayFilterFactory extends AbstractGatewayFilterFactory 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));
}
- /**
- * 从请求中获取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;
- }
}
diff --git a/epmet-gateway/src/main/java/com/epmet/filter/CpProperty.java b/epmet-gateway/src/main/java/com/epmet/filter/CpProperty.java
index f52d8f13a2..84872c0fb2 100644
--- a/epmet-gateway/src/main/java/com/epmet/filter/CpProperty.java
+++ b/epmet-gateway/src/main/java/com/epmet/filter/CpProperty.java
@@ -17,12 +17,15 @@ import java.util.List;
@ConfigurationProperties(prefix = "epmet")
public class CpProperty {
- private List urls;
+ /**
+ * 需要内部认证的url
+ */
+ private List internalAuthUrls;
/**
- * 白名单
+ * 需要外部认证的url
*/
- private List urlWhiteList;
+ private List externalAuthUrls;
/**
* 不处理token,直接通过
diff --git a/epmet-gateway/src/main/java/com/epmet/filter/UserTokenFilter.java b/epmet-gateway/src/main/java/com/epmet/filter/UserTokenFilter.java
deleted file mode 100644
index f66b0e6707..0000000000
--- a/epmet-gateway/src/main/java/com/epmet/filter/UserTokenFilter.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package com.epmet.filter;
-
-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.jwt.JwtTokenUtils;
-import io.jsonwebtoken.Claims;
-
-/**
- * 用户token的过滤器接口,提供通用的默认方法
- */
-public interface UserTokenFilter {
-
- default BaseTokenDto getBaseTokenDto(String token, JwtTokenUtils jwtTokenUtils) {
- //是否过期
- Claims claims = jwtTokenUtils.getClaimByToken(token);
- if (claims == null || jwtTokenUtils.isTokenExpired(claims.getExpiration())) {
-// throw new RenException(EpmetErrorCode.ERR401.getCode());
- 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);
- }
-
- default T getLoginUserInfoByToken(String token, JwtTokenUtils jwtTokenUtils, CpUserDetailRedis cpUserDetailRedis, Class clz) {
- BaseTokenDto baseTokenDto = getBaseTokenDto(token, jwtTokenUtils);
- //查询Redis
- return cpUserDetailRedis.get(baseTokenDto.getApp(), baseTokenDto.getClient(), baseTokenDto.getUserId(), clz);
- }
-
-}
diff --git a/epmet-gateway/src/main/java/com/epmet/jwt/JwtTokenUtils.java b/epmet-gateway/src/main/java/com/epmet/jwt/JwtTokenUtils.java
index 33baf31c52..452627b9a3 100644
--- a/epmet-gateway/src/main/java/com/epmet/jwt/JwtTokenUtils.java
+++ b/epmet-gateway/src/main/java/com/epmet/jwt/JwtTokenUtils.java
@@ -62,6 +62,18 @@ public class JwtTokenUtils {
}
}
+ public Claims getClaimByToken(String token, String secret) {
+ try {
+ return Jwts.parser()
+ .setSigningKey(secret)
+ .parseClaimsJws(token)
+ .getBody();
+ } catch (Exception e) {
+ logger.debug("validate is token error, token = " + token, e);
+ return null;
+ }
+ }
+
/**
* @return java.util.Date
* @param token
diff --git a/epmet-gateway/src/main/resources/bootstrap.yml b/epmet-gateway/src/main/resources/bootstrap.yml
index 9748b1ca26..750440f69f 100644
--- a/epmet-gateway/src/main/resources/bootstrap.yml
+++ b/epmet-gateway/src/main/resources/bootstrap.yml
@@ -415,8 +415,8 @@ ribbon:
ConnectTimeout: 300000
epmet:
- # 党群e事通(校验是否登录)
- urls:
+ # 内部认证,需要Authorization请求头
+ internalAuthUrls:
- /oper/customize/**
- /oper/crm/**
- /epmetuser/**
@@ -438,8 +438,8 @@ epmet:
- /resi/home/**
- /data/report/**
- # url认证白名单,先判断白名单,在白名单中的url直接放行,不再判断上述需要认证的名单
- urlWhiteList:
+ # 外部应用认证,使用AccessToken等头进行认证
+ externalAuthUrls:
- /data/report/test/test
- /data/report/screen/**
- /data/report/kcscreen/**
diff --git a/epmet-module/epmet-common-service/common-service-client/src/main/java/com/epmet/feign/EpmetCommonServiceOpenFeignClient.java b/epmet-module/epmet-common-service/common-service-client/src/main/java/com/epmet/feign/EpmetCommonServiceOpenFeignClient.java
index caa9bd6301..7ed9ff3f18 100644
--- a/epmet-module/epmet-common-service/common-service-client/src/main/java/com/epmet/feign/EpmetCommonServiceOpenFeignClient.java
+++ b/epmet-module/epmet-common-service/common-service-client/src/main/java/com/epmet/feign/EpmetCommonServiceOpenFeignClient.java
@@ -46,4 +46,11 @@ public interface EpmetCommonServiceOpenFeignClient {
*/
@PostMapping("/commonservice/externalapp/getcustomerids")
Result> getExternalCustomerIds();
+
+ /**
+ * 查询秘钥(仅限内部使用)
+ * @return
+ */
+ @PostMapping("/commonservice/externalapp/get-secret")
+ Result getSecret(@RequestBody String appId);
}
diff --git a/epmet-module/epmet-common-service/common-service-client/src/main/java/com/epmet/feign/fallback/EpmetCommonServiceOpenFeignClientFallback.java b/epmet-module/epmet-common-service/common-service-client/src/main/java/com/epmet/feign/fallback/EpmetCommonServiceOpenFeignClientFallback.java
index f21808fc8c..4640f13b45 100644
--- a/epmet-module/epmet-common-service/common-service-client/src/main/java/com/epmet/feign/fallback/EpmetCommonServiceOpenFeignClientFallback.java
+++ b/epmet-module/epmet-common-service/common-service-client/src/main/java/com/epmet/feign/fallback/EpmetCommonServiceOpenFeignClientFallback.java
@@ -34,4 +34,9 @@ public class EpmetCommonServiceOpenFeignClientFallback implements EpmetCommonSer
public Result> getExternalCustomerIds() {
return ModuleUtils.feignConError(ServiceConstant.EPMET_COMMON_SERVICE, "getExternalCustomerIds", null);
}
+
+ @Override
+ public Result getSecret(String appId) {
+ return ModuleUtils.feignConError(ServiceConstant.EPMET_COMMON_SERVICE, "getSecret", appId);
+ }
}
diff --git a/epmet-module/epmet-common-service/common-service-server/src/main/java/com/epmet/controller/ExternalAppController.java b/epmet-module/epmet-common-service/common-service-server/src/main/java/com/epmet/controller/ExternalAppController.java
index ffab33bbbe..f1229c7902 100644
--- a/epmet-module/epmet-common-service/common-service-server/src/main/java/com/epmet/controller/ExternalAppController.java
+++ b/epmet-module/epmet-common-service/common-service-server/src/main/java/com/epmet/controller/ExternalAppController.java
@@ -2,6 +2,7 @@ package com.epmet.controller;
import com.epmet.commons.tools.exception.EpmetErrorCode;
import com.epmet.commons.tools.exception.RenException;
+import com.epmet.commons.tools.exception.ValidateException;
import com.epmet.commons.tools.page.PageData;
import com.epmet.commons.tools.utils.Result;
import com.epmet.commons.tools.validator.ValidatorUtils;
@@ -10,6 +11,7 @@ import com.epmet.dto.form.ExternalAppFormDTO;
import com.epmet.dto.result.ExternalAppAuthResultDTO;
import com.epmet.dto.result.ExternalAppResultDTO;
import com.epmet.service.ExternalAppAuthService;
+import com.epmet.service.ExternalAppSecretService;
import com.epmet.service.ExternalAppService;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
@@ -34,6 +36,9 @@ public class ExternalAppController {
@Autowired
private ExternalAppService externalAppService;
+ @Autowired
+ private ExternalAppSecretService externalAppSecretService;
+
/**
* 外部请求认证
* @param formDTO
@@ -128,4 +133,17 @@ public class ExternalAppController {
return new Result().ok(newSecret);
}
+ /**
+ * 查询秘钥(仅限内部使用)
+ * @return
+ */
+ @PostMapping("/get-secret")
+ public Result getSecret(@RequestBody String appId) {
+ if (StringUtils.isBlank(appId)) {
+ throw new ValidateException(EpmetErrorCode.CUSTOMER_VALIDATE_ERROR.getCode(), "缺少应用ID参数");
+ }
+ String secret = externalAppSecretService.getSecretByAppId(appId);
+ return new Result().ok(secret);
+ }
+
}
diff --git a/epmet-module/epmet-common-service/common-service-server/src/main/java/com/epmet/dao/ExternalAppSecretDao.java b/epmet-module/epmet-common-service/common-service-server/src/main/java/com/epmet/dao/ExternalAppSecretDao.java
index fd2342c7c6..7faeae8ed4 100644
--- a/epmet-module/epmet-common-service/common-service-server/src/main/java/com/epmet/dao/ExternalAppSecretDao.java
+++ b/epmet-module/epmet-common-service/common-service-server/src/main/java/com/epmet/dao/ExternalAppSecretDao.java
@@ -41,4 +41,6 @@ public interface ExternalAppSecretDao extends BaseDao {
ExternalAppSecretEntity getSecretsByAppId(@Param("appId") String appId);
int updateSecret(@Param("appId") String appId, @Param("secret") String secret);
+
+ String getSecretByAppId(String appId);
}
\ No newline at end of file
diff --git a/epmet-module/epmet-common-service/common-service-server/src/main/java/com/epmet/service/ExternalAppSecretService.java b/epmet-module/epmet-common-service/common-service-server/src/main/java/com/epmet/service/ExternalAppSecretService.java
index 7f6be4bd5a..3a68251684 100644
--- a/epmet-module/epmet-common-service/common-service-server/src/main/java/com/epmet/service/ExternalAppSecretService.java
+++ b/epmet-module/epmet-common-service/common-service-server/src/main/java/com/epmet/service/ExternalAppSecretService.java
@@ -25,4 +25,5 @@ package com.epmet.service;
* @since v1.0.0 2020-08-18
*/
public interface ExternalAppSecretService {
+ String getSecretByAppId(String appId);
}
\ No newline at end of file
diff --git a/epmet-module/epmet-common-service/common-service-server/src/main/java/com/epmet/service/impl/ExternalAppSecretServiceImpl.java b/epmet-module/epmet-common-service/common-service-server/src/main/java/com/epmet/service/impl/ExternalAppSecretServiceImpl.java
index 567baf3fb2..da89e8ce1c 100644
--- a/epmet-module/epmet-common-service/common-service-server/src/main/java/com/epmet/service/impl/ExternalAppSecretServiceImpl.java
+++ b/epmet-module/epmet-common-service/common-service-server/src/main/java/com/epmet/service/impl/ExternalAppSecretServiceImpl.java
@@ -17,7 +17,9 @@
package com.epmet.service.impl;
+import com.epmet.dao.ExternalAppSecretDao;
import com.epmet.service.ExternalAppSecretService;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* 外部应用秘钥列表
@@ -28,4 +30,11 @@ import org.springframework.stereotype.Service;
@Service
public class ExternalAppSecretServiceImpl implements ExternalAppSecretService {
+ @Autowired
+ private ExternalAppSecretDao externalAppSecretDao;
+
+ @Override
+ public String getSecretByAppId(String appId) {
+ return externalAppSecretDao.getSecretByAppId(appId);
+ }
}
\ No newline at end of file
diff --git a/epmet-module/epmet-common-service/common-service-server/src/main/java/com/epmet/utils/externalapp/ExtAppJwtTokenUtils.java b/epmet-module/epmet-common-service/common-service-server/src/main/java/com/epmet/utils/externalapp/ExtAppJwtTokenUtils.java
index 490b2445e8..0f1674b319 100644
--- a/epmet-module/epmet-common-service/common-service-server/src/main/java/com/epmet/utils/externalapp/ExtAppJwtTokenUtils.java
+++ b/epmet-module/epmet-common-service/common-service-server/src/main/java/com/epmet/utils/externalapp/ExtAppJwtTokenUtils.java
@@ -80,14 +80,13 @@ public class ExtAppJwtTokenUtils {
//String appId = "acc4ad66c82a7b46e741364b4c62dce2";
// String customrId = "b09527201c4409e19d1dbc5e3c3429a1";
//孔村
- String secret = "657cd46d385a4c2ba6d9355aee24654ac3951deab7e6436e91201561b94969b5";
- String appId = "5efcfb775125d656f39583b8110a3d7d";
+ String secret = "c4096eb0497943c78327c5192621b209c38f20592f6a49cc8c79e8b77f3bd5c8";
+ String appId = "f358d63a89f3670c197c62ca4c3a0366";
String customrId = "2fe0065f70ca0e23ce4c26fca5f1d933";
claim.put("customerId", customrId);
claim.put("appId", appId);
- claim.put("customerId", customrId);
- long ts = System.currentTimeMillis() - 1000 * 60 * 4;
+ long ts = System.currentTimeMillis() + 1000 * 60 * 1;
System.out.println("时间戳:" + ts);
claim.put("ts", ts);
diff --git a/epmet-module/epmet-common-service/common-service-server/src/main/resources/mapper/ExternalAppSecretDao.xml b/epmet-module/epmet-common-service/common-service-server/src/main/resources/mapper/ExternalAppSecretDao.xml
index a192df36b1..f363e43d7c 100644
--- a/epmet-module/epmet-common-service/common-service-server/src/main/resources/mapper/ExternalAppSecretDao.xml
+++ b/epmet-module/epmet-common-service/common-service-server/src/main/resources/mapper/ExternalAppSecretDao.xml
@@ -40,5 +40,13 @@
AND DEL_FLAG = 0
+
+
+
\ No newline at end of file