diff --git a/epmet-commons/epmet-commons-openapi/pom.xml b/epmet-commons/epmet-commons-openapi/pom.xml new file mode 100644 index 0000000000..41093f03fa --- /dev/null +++ b/epmet-commons/epmet-commons-openapi/pom.xml @@ -0,0 +1,15 @@ + + + + epmet-commons + com.epmet + 2.0.0 + + 4.0.0 + + epmet-commons-openapi + + + diff --git a/epmet-commons/epmet-commons-openapi/src/main/java/com/epmet/openapi/constant/AuthTypes.java b/epmet-commons/epmet-commons-openapi/src/main/java/com/epmet/openapi/constant/AuthTypes.java new file mode 100644 index 0000000000..4f1c94af10 --- /dev/null +++ b/epmet-commons/epmet-commons-openapi/src/main/java/com/epmet/openapi/constant/AuthTypes.java @@ -0,0 +1,8 @@ +package com.epmet.openapi.constant; + +/** + * 认证方式 + */ +public interface AuthTypes { + String TAKE_TOKEN = "take_token"; +} diff --git a/epmet-commons/epmet-commons-openapi/src/main/java/com/epmet/openapi/constant/InClusterHeaderKeys.java b/epmet-commons/epmet-commons-openapi/src/main/java/com/epmet/openapi/constant/InClusterHeaderKeys.java new file mode 100644 index 0000000000..e2d0b2ca18 --- /dev/null +++ b/epmet-commons/epmet-commons-openapi/src/main/java/com/epmet/openapi/constant/InClusterHeaderKeys.java @@ -0,0 +1,10 @@ +package com.epmet.openapi.constant; + +/** + * 集群内的Header key + */ +public interface InClusterHeaderKeys { + + String APP_ID = "AppId"; + +} diff --git a/epmet-commons/epmet-commons-openapi/src/main/java/com/epmet/openapi/constant/RequestParamKeys.java b/epmet-commons/epmet-commons-openapi/src/main/java/com/epmet/openapi/constant/RequestParamKeys.java new file mode 100644 index 0000000000..b1d6bae806 --- /dev/null +++ b/epmet-commons/epmet-commons-openapi/src/main/java/com/epmet/openapi/constant/RequestParamKeys.java @@ -0,0 +1,14 @@ +package com.epmet.openapi.constant; + +/** + * url请求参数key + */ +public class RequestParamKeys { + + public static String APP_ID = "app_id"; + public static String AUTH_TYPE = "auth_type"; + public static String TIMESTAMP = "timestamp"; + public static String SIGN = "sign"; + public static String NONCE = "nonce"; + +} diff --git a/epmet-commons/epmet-commons-security/pom.xml b/epmet-commons/epmet-commons-security/pom.xml new file mode 100644 index 0000000000..a4bebe4c54 --- /dev/null +++ b/epmet-commons/epmet-commons-security/pom.xml @@ -0,0 +1,26 @@ + + + + epmet-commons + com.epmet + 2.0.0 + + 4.0.0 + + epmet-commons-security + + + + com.epmet + epmet-commons-tools + 2.0.0 + + + io.jsonwebtoken + jjwt + 0.7.0 + + + \ No newline at end of file diff --git a/epmet-commons/epmet-commons-security/src/main/java/com/epmet/commons/security/jwt/JwtUtils.java b/epmet-commons/epmet-commons-security/src/main/java/com/epmet/commons/security/jwt/JwtUtils.java new file mode 100644 index 0000000000..8df0b6cd8f --- /dev/null +++ b/epmet-commons/epmet-commons-security/src/main/java/com/epmet/commons/security/jwt/JwtUtils.java @@ -0,0 +1,131 @@ +/** + * Copyright (c) 2018 人人开源 All rights reserved. + *

+ * https://www.renren.io + *

+ * 版权所有,侵权必究! + */ + +package com.epmet.commons.security.jwt; + +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.SignatureAlgorithm; +import org.joda.time.DateTime; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +/** + * Jwt工具类 + * + * @author Mark sunlightcs@gmail.com + * @since 1.0.0 + */ +@Component +public class JwtUtils { + private static final Logger logger = LoggerFactory.getLogger(JwtUtils.class); + + 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 + * @Author yinzuomei + * @Description 获取token的有效期截止时间 + * @Date 2020/3/18 22:17 + **/ + public Date getExpiration(String token, String secret){ + try { + return Jwts.parser() + .setSigningKey(secret) + .parseClaimsJws(token) + .getBody().getExpiration(); + } catch (Exception e) { + logger.debug("validate is token error, token = " + token, e); + return null; + } + } + + /** + * @return java.lang.String + * @Author yinzuomei + * @Description 根据app+client+userId生成token + * @Date 2020/3/18 22:29 + **/ + public String createToken(Map claims, int expire, String secret) { + return Jwts.builder() + .setHeaderParam("typ", "JWT") + .setClaims(claims) + .setIssuedAt(new Date()) + .setExpiration(DateTime.now().plusSeconds(expire).toDate()) + .signWith(SignatureAlgorithm.HS512, secret) + .compact(); + } + + /** + * @Description 创建Token + * @return Token + * @param claims 载荷信息 + * @param expireTime 过期时间 + * @param secret 秘钥 + * @author wxz + * @date 2021.03.26 13:33 + */ + public String createToken(Map claims, Date expireTime, String secret) { + return Jwts.builder() + .setHeaderParam("typ", "JWT") + .setClaims(claims) + .setIssuedAt(new Date()) + .setExpiration(expireTime) + .signWith(SignatureAlgorithm.HS512, secret) + .compact(); + } + + /** + * token是否过期 + * + * @return true:过期 + */ + public boolean isTokenExpired(Date expiration) { + return expiration.before(new Date()); + } + + public static void main(String[] args) { + Map map=new HashMap<>(); + map.put("app","gov"); + map.put("client","wxmp"); + map.put("userId","100526ABC"); + String tokenStr=Jwts.builder() + .setHeaderParam("typ", "JWT") + .setClaims(map) + .setIssuedAt(new Date()) + .setExpiration(DateTime.now().plusSeconds(604800).toDate()) + .signWith(SignatureAlgorithm.HS512, "7016867071f0ebf1c46f123eaaf4b9d6[elink.epmet]") + .compact(); + System.out.println(tokenStr); + Claims claims= Jwts.parser() + .setSigningKey("7016867071f0ebf1c46f123eaaf4b9d6[elink.epmet]") + .parseClaimsJws(tokenStr) + .getBody(); + System.out.println("app="+ claims.get("app")); + System.out.println("client="+ claims.get("client")); + System.out.println("userId="+ claims.get("userId")); + } + +} diff --git a/epmet-commons/epmet-commons-security/src/main/java/com/epmet/commons/security/sign/openapi/OpenApiSignUtils.java b/epmet-commons/epmet-commons-security/src/main/java/com/epmet/commons/security/sign/openapi/OpenApiSignUtils.java new file mode 100644 index 0000000000..1de1b04f73 --- /dev/null +++ b/epmet-commons/epmet-commons-security/src/main/java/com/epmet/commons/security/sign/openapi/OpenApiSignUtils.java @@ -0,0 +1,109 @@ +package com.epmet.commons.security.sign.openapi; + +import com.epmet.commons.tools.utils.Md5Util; + +import java.util.*; + +/** + * OpenApi签名工具 + */ +public class OpenApiSignUtils { + + /** + * @Description 创建签名 + * @return + * @author wxz + * @date 2021.03.22 16:47 + */ + public static String createSign(Map contentMap, String signKey) { + String str2beSigned = mapToSignStr(contentMap); + str2beSigned = str2beSigned.concat("&sign_key=").concat(signKey); + return Md5Util.md5(str2beSigned); + } + + /** + * @Description 验签 + * @return + * @author wxz + * @date 2021.03.22 16:51 + */ + public static boolean checkSign(Map contentMap, String signKey) { + String newSign = createSign(contentMap, signKey); + return newSign.equals(contentMap.get("sign")); + } + + /** + * @Description map转化为签名明文 + * @return + * @author wxz + * @date 2021.03.22 16:47 + */ + public static String mapToSignStr(Map map) { + Set keySet = map.keySet(); + String[] keyArray = (String[])keySet.toArray(new String[keySet.size()]); + Arrays.sort(keyArray); + StringBuilder sb = new StringBuilder(); + + for(int i = 0; i < keyArray.length; ++i) { + String key = keyArray[i]; + String val = (String)map.get(key); + if (val != null && val.trim().length() > 0 && !"sign".equals(key)) { + if (!sb.toString().isEmpty()) { + sb.append("&"); + } + + sb.append(key).append("=").append((String)map.get(key)); + } + } + + return sb.toString(); + } + + public static void main(String[] args) { + generateGetAccessTokenSign(); + System.out.println("=============="); + generateGetOrgDetailSign(); + } + + private static void generateGetAccessTokenSign() { + long now = System.currentTimeMillis(); + System.out.println(now); + + String uuid = UUID.randomUUID().toString().replace("-", ""); + + HashMap content = new HashMap<>(); + content.put("app_id", "7d98b8af2d05752b4225709c4cfd4bd0"); + content.put("timestamp", String.valueOf(now)); + content.put("nonce", uuid); + content.put("auth_type", "take_token"); + + String secret = "3209ee9f41704482be1a1fb5873a25376f2899191ca846119d44168316bc3e44"; + + String sign = createSign(content, secret); + + System.out.println("时间戳:" + now); + System.out.println("随机数:" + uuid); + System.out.println("签名:" + sign); + } + + private static void generateGetOrgDetailSign() { + long now = System.currentTimeMillis(); + String uuid = UUID.randomUUID().toString().replace("-", "");; + System.out.println("时间戳:" + now); + System.out.println("随机数:" + uuid); + + HashMap content = new HashMap<>(); + //content.put("orgId", "aaa"); + //content.put("test", null); + content.put("gridId", "12128e0f614f1c00a058ea9a107033b2"); + content.put("app_id", "7d98b8af2d05752b4225709c4cfd4bd0"); + content.put("timestamp", String.valueOf(now)); + content.put("nonce", uuid); + content.put("auth_type", "take_token"); + + String secret = "3209ee9f41704482be1a1fb5873a25376f2899191ca846119d44168316bc3e44"; + + String sign = createSign(content, secret); + System.out.println("签名:" + sign); + } +} diff --git a/epmet-commons/epmet-commons-tools/src/main/java/com/epmet/commons/tools/exception/EpmetErrorCode.java b/epmet-commons/epmet-commons-tools/src/main/java/com/epmet/commons/tools/exception/EpmetErrorCode.java index 210f2d3443..5673b272f1 100644 --- a/epmet-commons/epmet-commons-tools/src/main/java/com/epmet/commons/tools/exception/EpmetErrorCode.java +++ b/epmet-commons/epmet-commons-tools/src/main/java/com/epmet/commons/tools/exception/EpmetErrorCode.java @@ -149,7 +149,16 @@ public enum EpmetErrorCode { TOPIC_IS_CLOSED(9008,"该话题已关闭,无法转为议题"), CUSTOMER_CATEGORY(9101,"分类已使用,不允许删除"), - CATEGORY_NAME(9102,"分类名称已存在,不允许重复"); + CATEGORY_NAME(9102,"分类名称已存在,不允许重复"), + + // open api异常 + OPEN_API_UNAUTHENTICATED(10100, "请求未认证"), + OPEN_API_TOKEN_EXPIRED(10102, "Token过期"), + OPEN_API_PARAMS_MISSING(10103, "参数不完整"), + OPEN_API_SIGN_ERROR(10104, "签名错误"), + OPEN_API_PARAMS_APPID_DIFF(10105, "app_id不一致"), // app_id在请求参数中和在token中不一致 + OPEN_API_REQUEST_EXPIRED(10106, "请求过期"), + OPEN_API_REQUEST_REPEAT(10107, "请求重复"); private int code; private String msg; diff --git a/epmet-commons/epmet-commons-tools/src/main/java/com/epmet/commons/tools/redis/RedisKeys.java b/epmet-commons/epmet-commons-tools/src/main/java/com/epmet/commons/tools/redis/RedisKeys.java index 9ddcadc507..763ce76d3e 100644 --- a/epmet-commons/epmet-commons-tools/src/main/java/com/epmet/commons/tools/redis/RedisKeys.java +++ b/epmet-commons/epmet-commons-tools/src/main/java/com/epmet/commons/tools/redis/RedisKeys.java @@ -380,6 +380,26 @@ public class RedisKeys { return rootPrefix.concat("badge:user:").concat(customerId).concat(":").concat(StringUtils.isBlank(userId) ? "*" : userId); } + /** + * @Description 获取openApi的accessToken的key + * @return + * @author wxz + * @date 2021.03.23 10:25 + */ + public static String getOpenApiAccessTokenKey(String appId) { + return rootPrefix.concat("openapi:accesstoken:").concat(appId); + } + + /** + * @Description 获取OpenApi请求随机数nonce + * @return + * @author wxz + * @date 2021.03.24 17:49 + */ + public static String getOpenApiNonceKey(String nonce) { + return rootPrefix.concat("openapi:nonce:").concat(nonce); + } + /** * desc: 根据文件路径获取oss 文件缓存key * diff --git a/epmet-commons/epmet-commons-tools/src/main/java/com/epmet/commons/tools/utils/ConvertUtils.java b/epmet-commons/epmet-commons-tools/src/main/java/com/epmet/commons/tools/utils/ConvertUtils.java index 93c653e178..6d2e509797 100644 --- a/epmet-commons/epmet-commons-tools/src/main/java/com/epmet/commons/tools/utils/ConvertUtils.java +++ b/epmet-commons/epmet-commons-tools/src/main/java/com/epmet/commons/tools/utils/ConvertUtils.java @@ -12,11 +12,14 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.BeanUtils; +import java.beans.BeanInfo; +import java.beans.IntrospectionException; +import java.beans.Introspector; +import java.beans.PropertyDescriptor; import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Map; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.*; /** * 转换工具类 @@ -87,4 +90,33 @@ public class ConvertUtils { } return t; } + + /** + * @Description entity转map + * @return + * @author wxz + * @date 2021.03.22 16:38 + */ + public static Map entityToMap(Object bean) throws IntrospectionException, InvocationTargetException, IllegalAccessException { + Class type = bean.getClass(); + Map returnMap = new HashMap(16); + BeanInfo beanInfo = Introspector.getBeanInfo(type); + PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors(); + + for(int i = 0; i < propertyDescriptors.length; ++i) { + PropertyDescriptor descriptor = propertyDescriptors[i]; + String propertyName = descriptor.getName(); + if (!"class".equals(propertyName)) { + Method readMethod = descriptor.getReadMethod(); + Object result = readMethod.invoke(bean); + if (result != null) { + returnMap.put(propertyName, String.valueOf(result)); + } else { + returnMap.put(propertyName, ""); + } + } + } + + return returnMap; + } } diff --git a/epmet-commons/pom.xml b/epmet-commons/pom.xml index 636480c48f..9e0d315827 100644 --- a/epmet-commons/pom.xml +++ b/epmet-commons/pom.xml @@ -25,6 +25,8 @@ epmet-commons-extapp-auth epmet-commons-thirdplat epmet-commons-rocketmq + epmet-commons-security + epmet-commons-openapi diff --git a/epmet-gateway/pom.xml b/epmet-gateway/pom.xml index 08eda7167e..af02a2054c 100644 --- a/epmet-gateway/pom.xml +++ b/epmet-gateway/pom.xml @@ -13,6 +13,11 @@ jar + + com.epmet + epmet-commons-security + 2.0.0 + com.epmet epmet-commons-tools @@ -65,6 +70,17 @@ common-service-client 2.0.0 + + com.epmet + epmet-commons-openapi + 2.0.0 + compile + + + com.epmet + epmet-commons-openapi + 2.0.0 + @@ -298,8 +314,8 @@ lb://gov-project-server - lb://common-service-server - + + http://localhost:8103 lb://resi-home-server @@ -329,8 +345,8 @@ lb://epmet-point-server - lb://epmet-ext-server - + + http://127.0.0.1:8113 lb://data-aggregator-server diff --git a/epmet-gateway/src/main/java/com/epmet/auth/ExtAppTakeTokenAuthProcessor.java b/epmet-gateway/src/main/java/com/epmet/auth/ExtAppTakeTokenAuthProcessor.java new file mode 100644 index 0000000000..6b527dc074 --- /dev/null +++ b/epmet-gateway/src/main/java/com/epmet/auth/ExtAppTakeTokenAuthProcessor.java @@ -0,0 +1,91 @@ +package com.epmet.auth; + +import com.epmet.commons.security.jwt.JwtUtils; +import com.epmet.commons.security.sign.openapi.OpenApiSignUtils; +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.Result; +import com.epmet.commons.tools.utils.SpringContextUtils; +import com.epmet.feign.EpmetCommonServiceOpenFeignClient; +import com.epmet.openapi.constant.InClusterHeaderKeys; +import com.epmet.openapi.constant.RequestParamKeys; +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jwts; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.server.reactive.ServerHttpRequest; +import org.springframework.stereotype.Component; +import org.springframework.web.server.ServerWebExchange; + +import java.util.Date; + +/** + * 外部应用认证处理器:来平台token的方式 + */ +@Component +public class ExtAppTakeTokenAuthProcessor extends ExtAppAuthProcessor { + + @Autowired + private JwtUtils jwtTokenUtils; + + @Autowired + private RedisUtils redisUtils; + + @Override + public void auth(String appId, String token, Long ts, ServerWebExchange exchange) { + String secret = getSecret(appId); + + // 1.过期验证 + String accessTokenInCache = redisUtils.getString(RedisKeys.getOpenApiAccessTokenKey(appId)); + Date expiration = jwtTokenUtils.getExpiration(token, secret); + if (StringUtils.isBlank(accessTokenInCache) || + expiration == null || + jwtTokenUtils.isTokenExpired(expiration) + ) { + + throw new RenException(EpmetErrorCode.OPEN_API_TOKEN_EXPIRED.getCode(), + EpmetErrorCode.OPEN_API_TOKEN_EXPIRED.getMsg()); + } + + // 2.验签 + // 验签暂时放到具体接口中,不放在gateway + //openApiSignUtils.checkSign(); + + // 2. 获取claims + Claims claims = jwtTokenUtils.getClaimByToken(token, secret); + String appIdInAccessToken = claims.get(RequestParamKeys.APP_ID, String.class); + + if (!appId.equals(appIdInAccessToken)) { + // 参数列表的appId和token中封装的不一致 + throw new RenException(EpmetErrorCode.OPEN_API_PARAMS_APPID_DIFF.getCode(), + EpmetErrorCode.OPEN_API_PARAMS_APPID_DIFF.getMsg()); + } + + // 3.将app_id放入header中 + ServerHttpRequest.Builder mutate = exchange.getRequest().mutate(); + mutate.header(InClusterHeaderKeys.APP_ID, new String[]{appId}); + exchange.mutate().request(mutate.build()).build(); + } + + /** + * @return + * @Description 获取秘钥 + * @author wxz + * @date 2021.03.23 14:12 + */ + private String getSecret(String appId) { + EpmetCommonServiceOpenFeignClient commonService = SpringContextUtils.getBean(EpmetCommonServiceOpenFeignClient.class); + Result result = commonService.getSecret(appId); + if (result == null || !result.success()) { + throw new RenException("fetchToken方式的外部应用认证,获取secret失败"); + } + String secret = result.getData(); + if (StringUtils.isBlank(secret)) { + throw new RenException("fetchToken方式的外部应用认证,获取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 index 8af2cdd5ef..d21ec692c5 100644 --- a/epmet-gateway/src/main/java/com/epmet/auth/ExternalAuthProcessor.java +++ b/epmet-gateway/src/main/java/com/epmet/auth/ExternalAuthProcessor.java @@ -4,6 +4,9 @@ import com.epmet.commons.tools.exception.EpmetErrorCode; import com.epmet.commons.tools.exception.ExceptionUtils; import com.epmet.commons.tools.exception.RenException; import com.epmet.filter.CpProperty; +import com.epmet.openapi.constant.AuthTypes; +import com.epmet.openapi.constant.RequestParamKeys; +import com.epmet.utils.ServerHttpRequestUtils; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -13,6 +16,7 @@ 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.util.MultiValueMap; import org.springframework.web.server.ServerWebExchange; /** @@ -31,17 +35,23 @@ public class ExternalAuthProcessor extends AuthProcessor { public static final String APP_ID_CUSTOMER_ID_KEY = "CustomerId"; public static final String APP_ID_AUTY_TYPE_KEY = "AuthType"; - // 认证方式 + /** + * 认证方式 + */ + // 调用方生成jwt public static final String APP_AUTH_TYPE_JWT = "jwt"; + // 调用方生成md5 public static final String APP_AUTH_TYPE_MD5 = "md5"; - @Autowired private ExtAppJwtAuthProcessor jwtAuthProcessor; @Autowired private ExtAppMD5AuthProcessor md5AuthProcessor; + @Autowired + private ExtAppTakeTokenAuthProcessor takeTokenAuthProcessor; + private final AntPathMatcher antPathMatcher = new AntPathMatcher(); @Autowired @@ -58,6 +68,7 @@ public class ExternalAuthProcessor extends AuthProcessor { for (String url : cpProperty.getExternalOpenUrls()) { if (antPathMatcher.match(url, requestUri)) { inPaths = true; + break; } } @@ -65,27 +76,46 @@ public class ExternalAuthProcessor extends AuthProcessor { throw new RenException(EpmetErrorCode.ERR401.getCode(), "所请求的url并未对外部应用开放"); } + // 放行白名单 + for (String url : cpProperty.getExternalAuthUrlsWhiteList()) { + if (antPathMatcher.match(url, requestUri)) { + return exchange; + } + } + HttpHeaders headers = request.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(EpmetErrorCode.ERR401.getCode(), "请求头中的AccessToken和AppId不能为空"); - } + String authType = getAuthType(headers, request); - logger.info("外部应用请求认证拦截Aspect执行,appId:{}, token:{}, ts:{}, customerId:{}, authType:{}", - appId, token, ts, customerId, authType); + logger.info("外部应用请求认证拦截Aspect执行,token:{}, ts:{}, customerId:{}, authType:{}", + token, ts, customerId, authType); // 没传authType或者传的jwt都用jwtprocessor处理 try { if (StringUtils.isBlank(authType) || APP_AUTH_TYPE_JWT.equals(authType)) { + String appId = headers.getFirst(APP_ID_HEADER_KEY); + if (StringUtils.isAnyBlank(token, appId)) { + throw new RenException(EpmetErrorCode.ERR401.getCode(), "请求头中的AccessToken和AppId不能为空"); + } jwtAuthProcessor.auth(appId, token, StringUtils.isNotBlank(ts) ? new Long(ts) : null, exchange); } else if (APP_AUTH_TYPE_MD5.equals(authType)) { + String appId = headers.getFirst(APP_ID_HEADER_KEY); + if (StringUtils.isAnyBlank(token, appId)) { + throw new RenException(EpmetErrorCode.ERR401.getCode(), "请求头中的AccessToken和AppId不能为空"); + } md5AuthProcessor.auth(appId, token, StringUtils.isNotBlank(ts) ? new Long(ts) : null, exchange); + } else if (AuthTypes.TAKE_TOKEN.equals(authType)) { + if (StringUtils.isBlank(token)) { + throw new RenException(EpmetErrorCode.OPEN_API_UNAUTHENTICATED.getCode()); + } + String appId = ServerHttpRequestUtils.getRequestParam(request, RequestParamKeys.APP_ID); + if (StringUtils.isBlank(appId)) { + throw new RenException(EpmetErrorCode.OPEN_API_PARAMS_MISSING.getCode(),"缺少参数:".concat(RequestParamKeys.APP_ID)); + } + takeTokenAuthProcessor.auth(appId, token, StringUtils.isNotBlank(ts) ? new Long(ts) : null, exchange); } else { throw new RenException(EpmetErrorCode.OPER_EXTERNAL_APP_AUTH_ERROR.getCode(), "未知的外部认证类型"); } @@ -100,4 +130,12 @@ public class ExternalAuthProcessor extends AuthProcessor { return exchange; } + + private String getAuthType(HttpHeaders headers, ServerHttpRequest request) { + String authType = ServerHttpRequestUtils.getRequestParam(request, RequestParamKeys.AUTH_TYPE); + if (StringUtils.isBlank(authType)) { + authType = headers.getFirst(APP_ID_AUTY_TYPE_KEY); + } + return authType; + } } 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 bb97dc2be7..9e6d7ef077 100644 --- a/epmet-gateway/src/main/java/com/epmet/filter/CpAuthGatewayFilterFactory.java +++ b/epmet-gateway/src/main/java/com/epmet/filter/CpAuthGatewayFilterFactory.java @@ -10,6 +10,9 @@ import com.epmet.commons.tools.utils.IpUtils; import com.epmet.commons.tools.utils.Result; import com.epmet.constant.AuthTypeConstant; import com.epmet.constant.TokenHeaderKeyConstant; +import com.epmet.openapi.constant.AuthTypes; +import com.epmet.openapi.constant.RequestParamKeys; +import com.epmet.utils.ServerHttpRequestUtils; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -111,6 +114,11 @@ public class CpAuthGatewayFilterFactory extends AbstractGatewayFilterFactory externalOpenUrls; + /** + * 对外开放url白名单 + */ + private List externalAuthUrlsWhiteList; + /** * 不处理token,直接通过 */ diff --git a/epmet-gateway/src/main/java/com/epmet/utils/ServerHttpRequestUtils.java b/epmet-gateway/src/main/java/com/epmet/utils/ServerHttpRequestUtils.java new file mode 100644 index 0000000000..334134baa1 --- /dev/null +++ b/epmet-gateway/src/main/java/com/epmet/utils/ServerHttpRequestUtils.java @@ -0,0 +1,19 @@ +package com.epmet.utils; + +import org.springframework.http.server.reactive.ServerHttpRequest; +import org.springframework.util.MultiValueMap; + +public class ServerHttpRequestUtils { + + /** + * @Description 从url中获取appId + * @return + * @author wxz + * @date 2021.03.25 15:13 + */ + public static String getRequestParam(ServerHttpRequest request, String paramName) { + MultiValueMap queryParams = request.getQueryParams(); + return queryParams.getFirst(paramName); + } + +} diff --git a/epmet-gateway/src/main/resources/bootstrap.yml b/epmet-gateway/src/main/resources/bootstrap.yml index 6c35fe31da..d797bc08bd 100644 --- a/epmet-gateway/src/main/resources/bootstrap.yml +++ b/epmet-gateway/src/main/resources/bootstrap.yml @@ -422,6 +422,10 @@ feign: okhttp: enabled: true +#logging: +# level: +# com.epmet: debug + hystrix: command: default: @@ -476,6 +480,11 @@ epmet: - /epmetuser/customerstaff/customerlist - /message/template/** - /data/aggregator/project/projectdistribution + + # 对外开放接口认证白名单 + externalAuthUrlsWhiteList: + - /epmet/ext/open-api/get-access-token + swaggerUrls: jwt: 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 66a1f46ee7..296489af6e 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 @@ -20,7 +20,7 @@ import java.util.Map; * @date 2020/6/4 10:28 */ @FeignClient(name = ServiceConstant.EPMET_COMMON_SERVICE, fallback = EpmetCommonServiceOpenFeignClientFallback.class) -// @FeignClient(name = ServiceConstant.EPMET_COMMON_SERVICE, fallback = EpmetCommonServiceOpenFeignClientFallback.class, url = "http://localhost:8103") + //@FeignClient(name = ServiceConstant.EPMET_COMMON_SERVICE, fallback = EpmetCommonServiceOpenFeignClientFallback.class, url = "http://192.168.1.132:8103") public interface EpmetCommonServiceOpenFeignClient { /** * @param formDTO diff --git a/epmet-module/epmet-ext/epmet-ext-client/src/main/java/com/epmet/dto/form/openapi/GetOrgDetailFormDTO.java b/epmet-module/epmet-ext/epmet-ext-client/src/main/java/com/epmet/dto/form/openapi/GetOrgDetailFormDTO.java new file mode 100644 index 0000000000..820225682a --- /dev/null +++ b/epmet-module/epmet-ext/epmet-ext-client/src/main/java/com/epmet/dto/form/openapi/GetOrgDetailFormDTO.java @@ -0,0 +1,15 @@ +package com.epmet.dto.form.openapi; + +import lombok.Data; + +import javax.validation.constraints.NotBlank; + +@Data +public class GetOrgDetailFormDTO extends OpenApiBaseFormDTO { + + @NotBlank(message = "orgId不能为空") + private String orgId; + + private String test; + +} diff --git a/epmet-module/epmet-ext/epmet-ext-client/src/main/java/com/epmet/dto/form/openapi/OpenApiBaseFormDTO.java b/epmet-module/epmet-ext/epmet-ext-client/src/main/java/com/epmet/dto/form/openapi/OpenApiBaseFormDTO.java new file mode 100644 index 0000000000..68f46e351b --- /dev/null +++ b/epmet-module/epmet-ext/epmet-ext-client/src/main/java/com/epmet/dto/form/openapi/OpenApiBaseFormDTO.java @@ -0,0 +1,31 @@ +package com.epmet.dto.form.openapi; + +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +/** + * open api基础类 + */ +@Data +public class OpenApiBaseFormDTO { + + public interface GetAccessTokenGroup {} + + @NotBlank(message = "签名不能为空", groups = { GetAccessTokenGroup.class }) + private String sign; + + /** + * 时间戳,ms + */ + @NotNull(message = "时间戳不能为空", groups = { GetAccessTokenGroup.class }) + private Long timestamp; + + /** + * 随机数,每次请求唯一 + */ + @NotBlank(message = "随机字段nonce不能为空", groups = { GetAccessTokenGroup.class }) + private String nonce; + +} diff --git a/epmet-module/epmet-ext/epmet-ext-client/src/main/java/com/epmet/dto/result/openapi/GetAccessTokenResultDTO.java b/epmet-module/epmet-ext/epmet-ext-client/src/main/java/com/epmet/dto/result/openapi/GetAccessTokenResultDTO.java new file mode 100644 index 0000000000..a913b25945 --- /dev/null +++ b/epmet-module/epmet-ext/epmet-ext-client/src/main/java/com/epmet/dto/result/openapi/GetAccessTokenResultDTO.java @@ -0,0 +1,12 @@ +package com.epmet.dto.result.openapi; + +import lombok.Data; + +@Data +public class GetAccessTokenResultDTO { + + private String accessToken; + + private Long expireTime; + +} diff --git a/epmet-module/epmet-ext/epmet-ext-server/pom.xml b/epmet-module/epmet-ext/epmet-ext-server/pom.xml index f33a428e27..9eda7325be 100644 --- a/epmet-module/epmet-ext/epmet-ext-server/pom.xml +++ b/epmet-module/epmet-ext/epmet-ext-server/pom.xml @@ -21,6 +21,21 @@ + + com.epmet + epmet-commons-openapi + 2.0.0 + + + com.epmet + common-service-client + 2.0.0 + + + com.epmet + epmet-commons-security + 2.0.0 + com.epmet epmet-ext-client diff --git a/epmet-module/epmet-ext/epmet-ext-server/src/main/java/com/epmet/annotation/OpenApiCheckSign.java b/epmet-module/epmet-ext/epmet-ext-server/src/main/java/com/epmet/annotation/OpenApiCheckSign.java new file mode 100644 index 0000000000..10bbcc156e --- /dev/null +++ b/epmet-module/epmet-ext/epmet-ext-server/src/main/java/com/epmet/annotation/OpenApiCheckSign.java @@ -0,0 +1,13 @@ +package com.epmet.annotation; + +import java.lang.annotation.*; + +/** + * OpenApi验签注解 + */ +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface OpenApiCheckSign { + +} diff --git a/epmet-module/epmet-ext/epmet-ext-server/src/main/java/com/epmet/aspect/OpenApiRequestCheckAspect.java b/epmet-module/epmet-ext/epmet-ext-server/src/main/java/com/epmet/aspect/OpenApiRequestCheckAspect.java new file mode 100644 index 0000000000..c6f23cc779 --- /dev/null +++ b/epmet-module/epmet-ext/epmet-ext-server/src/main/java/com/epmet/aspect/OpenApiRequestCheckAspect.java @@ -0,0 +1,218 @@ +package com.epmet.aspect; + +import com.epmet.commons.mybatis.aspect.DataFilterAspect; +import com.epmet.commons.security.sign.openapi.OpenApiSignUtils; +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.ConvertUtils; +import com.epmet.commons.tools.utils.Result; +import com.epmet.feign.EpmetCommonServiceOpenFeignClient; +import com.epmet.openapi.constant.RequestParamKeys; +import org.apache.commons.lang3.StringUtils; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; +import org.aspectj.lang.reflect.MethodSignature; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.context.request.RequestAttributes; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import javax.servlet.http.HttpServletRequest; +import java.lang.reflect.Method; +import java.lang.reflect.Parameter; +import java.util.HashMap; +import java.util.Map; + +/** + * OpenApi检查请求切面 + * 1.验签防止参数篡改 + * 2.timestamp+nonce防止请求重放攻击 + */ +@Aspect +@Component +@Order(1) +public class OpenApiRequestCheckAspect { + + @Autowired + private RedisUtils redisUtils; + + @Autowired + private EpmetCommonServiceOpenFeignClient commonServiceOpenFeignClient; + + //请求时差单位:s + long requestTimeSecDiff = 120; + //请求时差,单位:ms + long requestTimeMillSecDiff = requestTimeSecDiff * 1000;//单位:ms + + private static final Logger log = LoggerFactory.getLogger(DataFilterAspect.class); + + /** + * @Description 验签 + * @return + * @author wxz + * @date 2021.03.24 13:39 + */ + @Before("execution(* com.epmet.controller.*Controller*.*(..)) && @annotation(com.epmet.annotation.OpenApiCheckSign)") + public void check(JoinPoint point) { + Object[] args = point.getArgs(); + MethodSignature methodSignature = (MethodSignature) point.getSignature(); + Method method = methodSignature.getMethod(); + Parameter[] parameters = method.getParameters(); + + HttpServletRequest request = getRequest(); + + Map argMap = new HashMap<>(); + for (int i = 0; i < parameters.length; i++) { + if (parameters[i].isAnnotationPresent(RequestBody.class)) { + try { + argMap = ConvertUtils.entityToMap(args[i]); + } catch (Exception e) { + throw new RenException("验签参数转化发生异常"); + } + + break; + } + } + + fillRequestParamsInfoArgMap(argMap, request); + if (!OpenApiSignUtils.checkSign(argMap, getSecret(argMap.get(RequestParamKeys.APP_ID)))) { + // 验签失败 + throw new RenException(EpmetErrorCode.OPEN_API_SIGN_ERROR.getCode()); + } + checkRepeatRequest(argMap); + } + + /** + * @Description 填充url请求参数到map中,用来签名 + * @return + * @author wxz + * @date 2021.03.26 10:13 + */ + private void fillRequestParamsInfoArgMap(Map argMap, HttpServletRequest request) { + fillRequestParamsInfoArgMap(argMap, request, RequestParamKeys.APP_ID); + fillRequestParamsInfoArgMap(argMap, request, RequestParamKeys.AUTH_TYPE); + fillRequestParamsInfoArgMap(argMap, request, RequestParamKeys.NONCE); + fillRequestParamsInfoArgMap(argMap, request, RequestParamKeys.TIMESTAMP); + fillRequestParamsInfoArgMap(argMap, request, RequestParamKeys.SIGN); + } + + private void fillRequestParamsInfoArgMap(Map argMap, HttpServletRequest request, String paramName) { + String paramValue = request.getParameter(paramName); + if (StringUtils.isNotBlank(paramName)) { + argMap.put(paramName, paramValue); + } + } + + /** + * 检查请求重放 + * @param argMap + */ + void checkRepeatRequest(Map argMap) { + String timestampStr = argMap.get(RequestParamKeys.TIMESTAMP); + if (StringUtils.isBlank(timestampStr)) { + throw new RenException(EpmetErrorCode.OPEN_API_PARAMS_MISSING.getCode()); + } + long timestamp = Long.valueOf(timestampStr).longValue(); + long now = System.currentTimeMillis(); + + if (Math.abs(now - timestamp) > requestTimeMillSecDiff) { + // 只允许1分钟之内的请求,允许服务器之间时差为1分钟 + throw new RenException(EpmetErrorCode.OPEN_API_REQUEST_EXPIRED.getCode(), + String.format("请求已过期,允许时差为%s s", requestTimeSecDiff)); + } + String nonce = argMap.get(RequestParamKeys.NONCE); + String nonceInCache = redisUtils.getString(RedisKeys.getOpenApiNonceKey(nonce)); + if (StringUtils.isNotBlank(nonceInCache)) { + throw new RenException(EpmetErrorCode.OPEN_API_REQUEST_REPEAT.getCode()); + } + //将nonce缓存到redis,有效期1分钟 + redisUtils.set(RedisKeys.getOpenApiNonceKey(nonce), System.currentTimeMillis(), requestTimeSecDiff); + } + + /** + * @return + * @Description 取secret + * @author wxz + * @date 2021.03.24 12:49 + */ + private String getSecret(String appId) { + String secret = (String) redisUtils.get(RedisKeys.getExternalAppSecretKey(appId)); + if (StringUtils.isBlank(secret)) { + Result result = commonServiceOpenFeignClient.getSecret(appId); + if (!result.success()) { + throw new RenException("调用common service查询secret失败"); + } + secret = result.getData(); + if (StringUtils.isBlank(secret)) { + throw new RenException(String.format("根据appId%s没有找到对应的secret", appId)); + } + redisUtils.set(RedisKeys.getExternalAppSecretKey(appId), secret); + } + return secret; + } + + /** + * @return + * @Description 获取request + * @author wxz + * @date 2021.03.24 12:52 + */ + public HttpServletRequest getRequest() { + RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes(); + ServletRequestAttributes sra = (ServletRequestAttributes) requestAttributes; + return sra.getRequest(); + } + + /** + * @return + * @Description 获取appId + * @author wxz + * @date 2021.03.24 12:53 + */ + //public String getAppId(Parameter[] parameters, Object[] args) { + // HttpServletRequest request = getRequest(); + // String appId = request.getHeader("AppId"); + // if (StringUtils.isBlank(appId)) { + // for (int i = 0; i < parameters.length; i++) { + // if (parameters[i].isAnnotationPresent(RequestBody.class)) { + // Object arg = args[i]; + // try { + // appId = getAppIdFromDTO(arg); + // } catch (IllegalAccessException e) { + // e.printStackTrace(); + // } + // } + // } + // } + // if (StringUtils.isBlank(appId)) { + // throw new RenException("未携带AppId"); + // } + // return appId; + //} + + //private String getAppIdFromDTO(Object dto) throws IllegalAccessException { + // Field[] declaredFields = dto.getClass().getDeclaredFields(); + // for (int i = 0; i < declaredFields.length; i++) { + // Field field = declaredFields[i]; + // String fieldName = field.getName(); + // if ("appId".equals(fieldName)) { + // field.setAccessible(true); + // String value = (String) field.get(dto); + // return value; + // } + // } + // return null; + //} + + public static void main(String[] args) { + System.out.println(System.currentTimeMillis()); + } +} diff --git a/epmet-module/epmet-ext/epmet-ext-server/src/main/java/com/epmet/config/OpenApiConfig.java b/epmet-module/epmet-ext/epmet-ext-server/src/main/java/com/epmet/config/OpenApiConfig.java new file mode 100644 index 0000000000..706c01af35 --- /dev/null +++ b/epmet-module/epmet-ext/epmet-ext-server/src/main/java/com/epmet/config/OpenApiConfig.java @@ -0,0 +1,15 @@ +package com.epmet.config; + +import lombok.Data; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; +import org.springframework.stereotype.Component; + +@Component +@Data +public class OpenApiConfig { + + @Value("${openApi.accessToken.expire}") + private int accessTokenExpire; + +} diff --git a/epmet-module/epmet-ext/epmet-ext-server/src/main/java/com/epmet/controller/OpenApiAccessTokenController.java b/epmet-module/epmet-ext/epmet-ext-server/src/main/java/com/epmet/controller/OpenApiAccessTokenController.java new file mode 100644 index 0000000000..5f24502bfa --- /dev/null +++ b/epmet-module/epmet-ext/epmet-ext-server/src/main/java/com/epmet/controller/OpenApiAccessTokenController.java @@ -0,0 +1,60 @@ +package com.epmet.controller; + +import com.epmet.annotation.OpenApiCheckSign; +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.dto.result.openapi.GetAccessTokenResultDTO; +import com.epmet.feign.EpmetCommonServiceOpenFeignClient; +import com.epmet.service.OpenApiAccessTokenService; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequestMapping("open-api") +public class OpenApiAccessTokenController { + + @Autowired + private OpenApiAccessTokenService openApiAccessTokenService; + + @Autowired + private EpmetCommonServiceOpenFeignClient commonServiceOpenFeignClient; + + @Autowired + private RedisUtils redisUtils; + + private Logger logger = LoggerFactory.getLogger(OpenApiAccessTokenController.class); + + /** + * @Description 获取AccessToken + * @return + * @author wxz + * @date 2021.03.23 09:52 + */ + @OpenApiCheckSign + @PostMapping("get-access-token") + public Result getAccessToken(@RequestParam("app_id") String appId) { + // 1.取secret + String secret = (String)redisUtils.get(RedisKeys.getExternalAppSecretKey(appId)); + if (StringUtils.isBlank(secret)) { + Result result = commonServiceOpenFeignClient.getSecret(appId); + if (!result.success()) { + throw new RenException("调用common service查询secret失败"); + } + secret = result.getData(); + if (StringUtils.isBlank(secret)) { + throw new RenException(String.format("根据appId%s没有找到对应的secret", appId)); + } + redisUtils.set(RedisKeys.getExternalAppSecretKey(appId), secret); + } + + //2.生成token + GetAccessTokenResultDTO content = openApiAccessTokenService.getAccessToken(appId, secret); + return new Result().ok(content); + } + +} diff --git a/epmet-module/epmet-ext/epmet-ext-server/src/main/java/com/epmet/controller/OpenApiOrgController.java b/epmet-module/epmet-ext/epmet-ext-server/src/main/java/com/epmet/controller/OpenApiOrgController.java new file mode 100644 index 0000000000..30e97da2bf --- /dev/null +++ b/epmet-module/epmet-ext/epmet-ext-server/src/main/java/com/epmet/controller/OpenApiOrgController.java @@ -0,0 +1,27 @@ +package com.epmet.controller; + +import com.epmet.annotation.OpenApiCheckSign; +import com.epmet.commons.tools.utils.Result; +import com.epmet.dto.form.openapi.GetOrgDetailFormDTO; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequestMapping("open-api") +public class OpenApiOrgController { + + /** + * @Description OpenApiCheckSign是验签注解,OpenApi的接口请加上该注解 + * @return + * @author wxz + * @date 2021.03.24 12:55 + */ + @OpenApiCheckSign + @PostMapping("/get-org-detail") + public Result getOrgDetail(@RequestBody GetOrgDetailFormDTO input, + @RequestHeader("AppId") String appId) { + return new Result().ok("测试org"); + } + + + +} diff --git a/epmet-module/epmet-ext/epmet-ext-server/src/main/java/com/epmet/service/OpenApiAccessTokenService.java b/epmet-module/epmet-ext/epmet-ext-server/src/main/java/com/epmet/service/OpenApiAccessTokenService.java new file mode 100644 index 0000000000..2b6d362636 --- /dev/null +++ b/epmet-module/epmet-ext/epmet-ext-server/src/main/java/com/epmet/service/OpenApiAccessTokenService.java @@ -0,0 +1,17 @@ +package com.epmet.service; + +import com.epmet.dto.result.openapi.GetAccessTokenResultDTO; + +/** + * access token的service + */ +public interface OpenApiAccessTokenService { + + /** + * @Description 获取AccessToken + * @return + * @author wxz + * @date 2021.03.22 22:57 + */ + GetAccessTokenResultDTO getAccessToken(String appId, String secret); +} diff --git a/epmet-module/epmet-ext/epmet-ext-server/src/main/java/com/epmet/service/impl/OpenApiAccessTokenServiceImpl.java b/epmet-module/epmet-ext/epmet-ext-server/src/main/java/com/epmet/service/impl/OpenApiAccessTokenServiceImpl.java new file mode 100644 index 0000000000..fad64083db --- /dev/null +++ b/epmet-module/epmet-ext/epmet-ext-server/src/main/java/com/epmet/service/impl/OpenApiAccessTokenServiceImpl.java @@ -0,0 +1,45 @@ +package com.epmet.service.impl; + +import com.epmet.commons.security.jwt.JwtUtils; +import com.epmet.commons.tools.redis.RedisKeys; +import com.epmet.commons.tools.redis.RedisUtils; +import com.epmet.config.OpenApiConfig; +import com.epmet.dto.result.openapi.GetAccessTokenResultDTO; +import com.epmet.openapi.constant.RequestParamKeys; +import com.epmet.service.OpenApiAccessTokenService; +import org.joda.time.DateTime; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.Date; +import java.util.HashMap; + +@Service +public class OpenApiAccessTokenServiceImpl implements OpenApiAccessTokenService { + + @Autowired + private JwtUtils jwtTokenUtils; + + @Autowired + private OpenApiConfig openApiConfig; + + @Autowired + private RedisUtils redisUtils; + + @Override + public GetAccessTokenResultDTO getAccessToken(String appId, String secret) { + HashMap claim = new HashMap<>(); + claim.put(RequestParamKeys.APP_ID, appId); + + Date expireTime = DateTime.now().plusSeconds(openApiConfig.getAccessTokenExpire()).toDate(); + String token = jwtTokenUtils.createToken(claim, expireTime, secret); + // 缓存token + redisUtils.set(RedisKeys.getOpenApiAccessTokenKey(appId), token, openApiConfig.getAccessTokenExpire()); + + GetAccessTokenResultDTO content = new GetAccessTokenResultDTO(); + content.setAccessToken(token); + content.setExpireTime(expireTime.getTime()); + + return content; + } +} diff --git a/epmet-module/epmet-ext/epmet-ext-server/src/main/resources/bootstrap.yml b/epmet-module/epmet-ext/epmet-ext-server/src/main/resources/bootstrap.yml index 1ed5a4306d..881881db27 100644 --- a/epmet-module/epmet-ext/epmet-ext-server/src/main/resources/bootstrap.yml +++ b/epmet-module/epmet-ext/epmet-ext-server/src/main/resources/bootstrap.yml @@ -110,3 +110,8 @@ shutdown: graceful: enable: true #是否开启优雅停机 waitTimeSecs: 30 # 优雅停机等待时间,超过30秒,发出告警 + +# 对外开放接口配置 +openApi: + accessToken: + expire: 7200 diff --git a/pom.xml b/pom.xml index b0d6621300..9420c9ff24 100644 --- a/pom.xml +++ b/pom.xml @@ -29,7 +29,7 @@ epmet-module epmet-user epmet-openapi - + UTF-8