Browse Source

新增:

接口手动验签
dev
wxz 4 years ago
parent
commit
604c78541a
  1. 4
      epmet-commons/epmet-commons-security/src/main/java/com/epmet/commons/security/jwt/JwtUtils.java
  2. 3
      epmet-commons/epmet-commons-security/src/main/java/com/epmet/commons/security/sign/openapi/OpenApiSignUtils.java
  3. 3
      epmet-commons/epmet-commons-tools/src/main/java/com/epmet/commons/tools/exception/EpmetErrorCode.java
  4. 4
      epmet-commons/epmet-commons-tools/src/main/java/com/epmet/commons/tools/redis/RedisKeys.java
  5. 9
      epmet-gateway/pom.xml
  6. 84
      epmet-gateway/src/main/java/com/epmet/auth/ExtAppFetchTokenAuthProcessor.java
  7. 30
      epmet-gateway/src/main/java/com/epmet/auth/ExternalAuthProcessor.java
  8. 4
      epmet-gateway/src/main/resources/bootstrap.yml
  9. 2
      epmet-module/epmet-common-service/common-service-client/src/main/java/com/epmet/feign/EpmetCommonServiceOpenFeignClient.java
  10. 15
      epmet-module/epmet-ext/epmet-ext-client/src/main/java/com/epmet/dto/form/openapi/GetOrgDetailFormDTO.java
  11. 13
      epmet-module/epmet-ext/epmet-ext-client/src/main/java/com/epmet/dto/form/openapi/OpenApiBaseFormDTO.java
  12. 63
      epmet-module/epmet-ext/epmet-ext-server/src/main/java/com/epmet/controller/OpenApiOrgController.java
  13. 13
      epmet-module/epmet-ext/epmet-ext-server/src/main/java/com/epmet/service/impl/OpenApiAccessTokenServiceImpl.java

4
epmet-commons/epmet-commons-security/src/main/java/com/epmet/commons/security/jwt/JwtTokenUtils.java → epmet-commons/epmet-commons-security/src/main/java/com/epmet/commons/security/jwt/JwtUtils.java

@ -28,8 +28,8 @@ import java.util.Map;
* @since 1.0.0 * @since 1.0.0
*/ */
@Component @Component
public class JwtTokenUtils { public class JwtUtils {
private static final Logger logger = LoggerFactory.getLogger(JwtTokenUtils.class); private static final Logger logger = LoggerFactory.getLogger(JwtUtils.class);
public Claims getClaimByToken(String token, String secret) { public Claims getClaimByToken(String token, String secret) {
try { try {

3
epmet-commons/epmet-commons-security/src/main/java/com/epmet/commons/security/sign/openapi/OpenApiSignUtils.java

@ -66,7 +66,8 @@ public class OpenApiSignUtils {
public static void main(String[] args) { public static void main(String[] args) {
HashMap<String, String> content = new HashMap<>(); HashMap<String, String> content = new HashMap<>();
content.put("appId", "7d98b8af2d05752b4225709c4cfd4bd0"); content.put("orgId", "aaa");
content.put("test", "");
String secret = "3209ee9f41704482be1a1fb5873a25376f2899191ca846119d44168316bc3e44"; String secret = "3209ee9f41704482be1a1fb5873a25376f2899191ca846119d44168316bc3e44";

3
epmet-commons/epmet-commons-tools/src/main/java/com/epmet/commons/tools/exception/EpmetErrorCode.java

@ -146,7 +146,8 @@ public enum EpmetErrorCode {
TOPIC_IS_CLOSED(9008,"该话题已关闭,无法转为议题"), TOPIC_IS_CLOSED(9008,"该话题已关闭,无法转为议题"),
// open api异常 // open api异常
OPEN_API_SIGN_ERROR(9100, "签名错误"); OPEN_API_SIGN_ERROR(9100, "签名错误"),
OPEN_API_SIGN_TOKEN_EXPIRED(9101, "Token过期");
private int code; private int code;
private String msg; private String msg;

4
epmet-commons/epmet-commons-tools/src/main/java/com/epmet/commons/tools/redis/RedisKeys.java

@ -377,7 +377,7 @@ public class RedisKeys {
* @author wxz * @author wxz
* @date 2021.03.23 10:25 * @date 2021.03.23 10:25
*/ */
public static String getOpenApiAccessTokenKey(String appId) { public static String getOpenApiAccessTokenKey(String accessToken) {
return rootPrefix.concat("openapi:accesstoken:").concat(appId); return rootPrefix.concat("openapi:accesstoken:").concat(accessToken);
} }
} }

9
epmet-gateway/pom.xml

@ -13,6 +13,11 @@
<packaging>jar</packaging> <packaging>jar</packaging>
<dependencies> <dependencies>
<dependency>
<groupId>com.epmet</groupId>
<artifactId>epmet-commons-security</artifactId>
<version>2.0.0</version>
</dependency>
<dependency> <dependency>
<groupId>com.epmet</groupId> <groupId>com.epmet</groupId>
<artifactId>epmet-commons-tools</artifactId> <artifactId>epmet-commons-tools</artifactId>
@ -329,8 +334,8 @@
<gateway.routes.epmet-point-server.url>lb://epmet-point-server</gateway.routes.epmet-point-server.url> <gateway.routes.epmet-point-server.url>lb://epmet-point-server</gateway.routes.epmet-point-server.url>
<!-- <gateway.routes.epmet-point-server.url>http://127.0.0.1:8112</gateway.routes.epmet-point-server.url>--> <!-- <gateway.routes.epmet-point-server.url>http://127.0.0.1:8112</gateway.routes.epmet-point-server.url>-->
<!-- 34、 开放接口服务 --> <!-- 34、 开放接口服务 -->
<gateway.routes.epmet-ext-server.url>lb://epmet-ext-server</gateway.routes.epmet-ext-server.url> <!--<gateway.routes.epmet-ext-server.url>lb://epmet-ext-server</gateway.routes.epmet-ext-server.url>-->
<!-- <gateway.routes.epmet-ext-server.url>http://127.0.0.1:8113</gateway.routes.epmet-ext-server.url>--> <gateway.routes.epmet-ext-server.url>http://127.0.0.1:8113</gateway.routes.epmet-ext-server.url>
<!-- 35、多数据源服务 --> <!-- 35、多数据源服务 -->
<gateway.routes.data-aggregator-server.url>lb://data-aggregator-server</gateway.routes.data-aggregator-server.url> <gateway.routes.data-aggregator-server.url>lb://data-aggregator-server</gateway.routes.data-aggregator-server.url>

84
epmet-gateway/src/main/java/com/epmet/auth/ExtAppFetchTokenAuthProcessor.java

@ -0,0 +1,84 @@
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 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;
/**
* 外部应用认证处理器来平台token的方式
*/
@Component
public class ExtAppFetchTokenAuthProcessor extends ExtAppAuthProcessor {
@Autowired
private JwtUtils jwtTokenUtils;
@Autowired
private RedisUtils redisUtils;
@Override
public void auth(String appId, String token, Long ts, ServerWebExchange exchange) {
// 这种方式不需要其他平台传appId,因此我们自己从redis中取
appId = (String) redisUtils.get(RedisKeys.getOpenApiAccessTokenKey(token));
// 1.token过期校验
if (StringUtils.isBlank(appId)) {
throw new RenException(EpmetErrorCode.OPEN_API_SIGN_TOKEN_EXPIRED.getCode(),
EpmetErrorCode.OPEN_API_SIGN_TOKEN_EXPIRED.getMsg());
}
String secret = getSecret(appId);
if (jwtTokenUtils.isTokenExpired(jwtTokenUtils.getExpiration(token, secret))) {
throw new RenException(EpmetErrorCode.OPEN_API_SIGN_TOKEN_EXPIRED.getCode(),
EpmetErrorCode.OPEN_API_SIGN_TOKEN_EXPIRED.getMsg());
}
// 2.验签
// 验签暂时放到具体接口中
//openApiSignUtils.checkSign();
// 2. 获取claims
Claims claims = jwtTokenUtils.getClaimByToken(token, secret);
appId = claims.get("appId", String.class);
if (!StringUtils.isBlank(appId)) {
ServerHttpRequest.Builder mutate = exchange.getRequest().mutate();
mutate.header("appId", appId);
exchange.mutate().request(mutate.build()).build();
}
}
/**
* @Description 获取秘钥
* @return
* @author wxz
* @date 2021.03.23 14:12
*/
private String getSecret(String appId) {
EpmetCommonServiceOpenFeignClient commonService = SpringContextUtils.getBean(EpmetCommonServiceOpenFeignClient.class);
Result<String> 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;
}
}

30
epmet-gateway/src/main/java/com/epmet/auth/ExternalAuthProcessor.java

@ -31,9 +31,15 @@ public class ExternalAuthProcessor extends AuthProcessor {
public static final String APP_ID_CUSTOMER_ID_KEY = "CustomerId"; 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_ID_AUTY_TYPE_KEY = "AuthType";
// 认证方式 /**
* 认证方式
*/
// 调用方生成jwt
public static final String APP_AUTH_TYPE_JWT = "jwt"; public static final String APP_AUTH_TYPE_JWT = "jwt";
// 调用方生成md5
public static final String APP_AUTH_TYPE_MD5 = "md5"; public static final String APP_AUTH_TYPE_MD5 = "md5";
// 获取token方式
public static final String APP_AUTH_TYPE_FETCH_TOKEN = "fetchToken";
@Autowired @Autowired
@ -42,6 +48,9 @@ public class ExternalAuthProcessor extends AuthProcessor {
@Autowired @Autowired
private ExtAppMD5AuthProcessor md5AuthProcessor; private ExtAppMD5AuthProcessor md5AuthProcessor;
@Autowired
private ExtAppFetchTokenAuthProcessor fetchTokenAuthProcessor;
private final AntPathMatcher antPathMatcher = new AntPathMatcher(); private final AntPathMatcher antPathMatcher = new AntPathMatcher();
@Autowired @Autowired
@ -68,24 +77,29 @@ public class ExternalAuthProcessor extends AuthProcessor {
HttpHeaders headers = request.getHeaders(); HttpHeaders headers = request.getHeaders();
String token = headers.getFirst(ACCESS_TOKEN_HEADER_KEY); 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 ts = headers.getFirst(APP_ID_TIMESTAMP_KEY);
String customerId = headers.getFirst(APP_ID_CUSTOMER_ID_KEY); String customerId = headers.getFirst(APP_ID_CUSTOMER_ID_KEY);
String authType = headers.getFirst(APP_ID_AUTY_TYPE_KEY); String authType = headers.getFirst(APP_ID_AUTY_TYPE_KEY);
if (StringUtils.isAnyBlank(token, appId)) { logger.info("外部应用请求认证拦截Aspect执行,token:{}, ts:{}, customerId:{}, authType:{}",
throw new RenException(EpmetErrorCode.ERR401.getCode(), "请求头中的AccessToken和AppId不能为空"); token, ts, customerId, authType);
}
logger.info("外部应用请求认证拦截Aspect执行,appId:{}, token:{}, ts:{}, customerId:{}, authType:{}",
appId, token, ts, customerId, authType);
// 没传authType或者传的jwt都用jwtprocessor处理 // 没传authType或者传的jwt都用jwtprocessor处理
try { try {
if (StringUtils.isBlank(authType) || APP_AUTH_TYPE_JWT.equals(authType)) { 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); jwtAuthProcessor.auth(appId, token, StringUtils.isNotBlank(ts) ? new Long(ts) : null, exchange);
} else if (APP_AUTH_TYPE_MD5.equals(authType)) { } 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); md5AuthProcessor.auth(appId, token, StringUtils.isNotBlank(ts) ? new Long(ts) : null, exchange);
} else if (APP_AUTH_TYPE_FETCH_TOKEN.equals(authType)) {
fetchTokenAuthProcessor.auth(null, token, StringUtils.isNotBlank(ts) ? new Long(ts) : null, exchange);
} else { } else {
throw new RenException(EpmetErrorCode.OPER_EXTERNAL_APP_AUTH_ERROR.getCode(), "未知的外部认证类型"); throw new RenException(EpmetErrorCode.OPER_EXTERNAL_APP_AUTH_ERROR.getCode(), "未知的外部认证类型");
} }

4
epmet-gateway/src/main/resources/bootstrap.yml

@ -422,6 +422,10 @@ feign:
httpclient: httpclient:
enabled: true enabled: true
logging:
level:
com.epmet: debug
hystrix: hystrix:
command: command:
default: default:

2
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 * @date 2020/6/4 10:28
*/ */
@FeignClient(name = ServiceConstant.EPMET_COMMON_SERVICE, fallback = EpmetCommonServiceOpenFeignClientFallback.class) @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 { public interface EpmetCommonServiceOpenFeignClient {
/** /**
* @param formDTO * @param formDTO

15
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;
}

13
epmet-module/epmet-ext/epmet-ext-client/src/main/java/com/epmet/dto/form/openapi/OpenApiBaseFormDTO.java

@ -0,0 +1,13 @@
package com.epmet.dto.form.openapi;
import lombok.Data;
/**
* open api基础类
*/
@Data
public class OpenApiBaseFormDTO {
private String sign;
}

63
epmet-module/epmet-ext/epmet-ext-server/src/main/java/com/epmet/controller/OpenApiOrgController.java

@ -0,0 +1,63 @@
package com.epmet.controller;
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.dto.form.openapi.GetOrgDetailFormDTO;
import com.epmet.feign.EpmetCommonServiceOpenFeignClient;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.Map;
@RestController
@RequestMapping("open-api")
public class OpenApiOrgController {
@Autowired
private EpmetCommonServiceOpenFeignClient commonServiceOpenFeignClient;
@Autowired
private RedisUtils redisUtils;
@PostMapping("/get-org-detail")
public Result getOrgDetail(@RequestBody GetOrgDetailFormDTO input,
@RequestHeader("appId") String appId) {
// 验签
Map<String, String> params = null;
try {
params = ConvertUtils.entityToMap(input);
} catch (Exception e) {
e.printStackTrace();
}
if (!OpenApiSignUtils.checkSign(params, getSecret(appId))) {
// 验签失败,抛出异常提示
throw new RenException(EpmetErrorCode.OPEN_API_SIGN_ERROR.getCode());
}
return new Result().ok("测试org");
}
private String getSecret(String appId) {
String secret = (String)redisUtils.get(RedisKeys.getExternalAppSecretKey(appId));
if (StringUtils.isBlank(secret)) {
Result<String> 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;
}
}

13
epmet-module/epmet-ext/epmet-ext-server/src/main/java/com/epmet/service/impl/OpenApiAccessTokenServiceImpl.java

@ -1,18 +1,11 @@
package com.epmet.service.impl; package com.epmet.service.impl;
import com.epmet.commons.security.jwt.JwtTokenUtils; import com.epmet.commons.security.jwt.JwtUtils;
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.RedisKeys;
import com.epmet.commons.tools.redis.RedisUtils; import com.epmet.commons.tools.redis.RedisUtils;
import com.epmet.commons.tools.utils.Result;
import com.epmet.commons.tools.utils.SpringContextUtils;
import com.epmet.config.OpenApiConfig; import com.epmet.config.OpenApiConfig;
import com.epmet.feign.EpmetCommonServiceOpenFeignClient;
import com.epmet.service.OpenApiAccessTokenService; import com.epmet.service.OpenApiAccessTokenService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.HashMap; import java.util.HashMap;
@ -21,7 +14,7 @@ import java.util.HashMap;
public class OpenApiAccessTokenServiceImpl implements OpenApiAccessTokenService { public class OpenApiAccessTokenServiceImpl implements OpenApiAccessTokenService {
@Autowired @Autowired
private JwtTokenUtils jwtTokenUtils; private JwtUtils jwtTokenUtils;
@Autowired @Autowired
private OpenApiConfig openApiConfig; private OpenApiConfig openApiConfig;
@ -37,7 +30,7 @@ public class OpenApiAccessTokenServiceImpl implements OpenApiAccessTokenService
String token = jwtTokenUtils.createToken(claim, openApiConfig.getAccessTokenExpire(), secret); String token = jwtTokenUtils.createToken(claim, openApiConfig.getAccessTokenExpire(), secret);
// 缓存token // 缓存token
redisUtils.set(RedisKeys.getOpenApiAccessTokenKey(appId), token, openApiConfig.getAccessTokenExpire()); redisUtils.set(RedisKeys.getOpenApiAccessTokenKey(token), appId, openApiConfig.getAccessTokenExpire());
return token; return token;
} }

Loading…
Cancel
Save