diff --git a/sop-gateway/pom.xml b/sop-gateway/pom.xml
index 385e8a82..dc4ad9b2 100644
--- a/sop-gateway/pom.xml
+++ b/sop-gateway/pom.xml
@@ -67,6 +67,16 @@
1.18.4
provided
+
+
+ org.springframework.boot
+ spring-boot-starter-data-redis
+
+
+
+ org.apache.commons
+ commons-lang3
+
diff --git a/sop-gateway/src/main/java/com/gitee/sop/gateway/config/MyConfig.java b/sop-gateway/src/main/java/com/gitee/sop/gateway/config/MyConfig.java
index 9d32bba9..d9d0475a 100644
--- a/sop-gateway/src/main/java/com/gitee/sop/gateway/config/MyConfig.java
+++ b/sop-gateway/src/main/java/com/gitee/sop/gateway/config/MyConfig.java
@@ -1,23 +1,48 @@
package com.gitee.sop.gateway.config;
+import com.alibaba.fastjson.JSONObject;
import com.gitee.sop.gatewaycommon.bean.ApiConfig;
+import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
+@Slf4j
@Component
public class MyConfig {
+ @Autowired
+ private StringRedisTemplate redisTemplate;
+ private static String APP_AUTH_TOKEN_PREFIX = "com.gitee.sop.oauth2_access_token:";
+
+ public static String getAccessTokenKey(String accessToken) {
+ return APP_AUTH_TOKEN_PREFIX + accessToken;
+ }
+
+
@PostConstruct
public void after() {
ApiConfig.getInstance().setTokenValidator(apiParam -> {
// 获取客户端传递过来的token
- String token = apiParam.fetchAccessToken();
- return !StringUtils.isBlank(token);
- // TODO: 校验token有效性,可以从redis中读取
+ try {
+ String token = apiParam.fetchAccessToken();
+ if (StringUtils.isBlank(token)) {
+ return Boolean.FALSE;
+ }
+ String json = redisTemplate.opsForValue().get(getAccessTokenKey(token));
+ if(StringUtils.isEmpty(json)) {
+ return Boolean.FALSE;
+ }
- // 返回true表示这个token真实、有效
+ JSONObject userInfo = JSONObject.parseObject(json);
+ return userInfo != null;
+ } catch (Exception e) {
+ log.error("redisError", e);
+ return Boolean.FALSE;
+ }
});
}
}
\ No newline at end of file
diff --git a/sop-gateway/src/main/resources/application-dev.properties b/sop-gateway/src/main/resources/application-dev.properties
index 0ba27c4c..e0420b8f 100644
--- a/sop-gateway/src/main/resources/application-dev.properties
+++ b/sop-gateway/src/main/resources/application-dev.properties
@@ -13,4 +13,14 @@ register.url=127.0.0.1:8848
# 如果需要传输大文本可以把值设置高一点
spring.codec.max-in-memory-size=262144
-logging.level.com.gitee=debug
\ No newline at end of file
+logging.level.com.gitee=debug
+
+spring.redis.host=localhost
+spring.redis.port=6379
+spring.redis.jedis.pool.min-idle=1
+spring.redis.jedis.pool.max-idle=5
+spring.redis.jedis.pool.max-wait=-1
+spring.redis.jedis.pool.max-active=8
+spring.redis.timeout=60000
+spring.redis.database=0
+spring.redis.password=
\ No newline at end of file
diff --git a/sop-openapi/pom.xml b/sop-openapi/pom.xml
index 1f74e3c7..f035b864 100644
--- a/sop-openapi/pom.xml
+++ b/sop-openapi/pom.xml
@@ -80,6 +80,13 @@
net.oschina.durcframework
fastmybatis-spring-boot-starter
+
+
+ org.projectlombok
+ lombok
+ 1.18.4
+ provided
+
diff --git a/sop-openapi/src/main/java/com/gitee/sop/openapi/SopOpenapiApplication.java b/sop-openapi/src/main/java/com/gitee/sop/openapi/SopOpenapiApplication.java
index c3479299..29675788 100644
--- a/sop-openapi/src/main/java/com/gitee/sop/openapi/SopOpenapiApplication.java
+++ b/sop-openapi/src/main/java/com/gitee/sop/openapi/SopOpenapiApplication.java
@@ -1,8 +1,14 @@
package com.gitee.sop.openapi;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
+
+@EnableDiscoveryClient
+@SpringBootApplication
public class SopOpenapiApplication {
public static void main(String[] args) {
-
+ SpringApplication.run(SopOpenapiApplication.class, args);
}
}
diff --git a/sop-openapi/src/main/java/com/gitee/sop/openapi/entity/IsvAuthTokenEntity.java b/sop-openapi/src/main/java/com/gitee/sop/openapi/entity/IsvAuthTokenEntity.java
index 011b4ea3..2fae85fa 100644
--- a/sop-openapi/src/main/java/com/gitee/sop/openapi/entity/IsvAuthTokenEntity.java
+++ b/sop-openapi/src/main/java/com/gitee/sop/openapi/entity/IsvAuthTokenEntity.java
@@ -32,6 +32,12 @@ public class IsvAuthTokenEntity {
/** 1启用,2禁用, 数据库字段:status */
private Byte status;
+ /** appAuthCode 数据库字段:app_auth_code */
+ private String appAuthCode;
+
/** appAuthToken 数据库字段:app_auth_token */
private String appAuthToken;
+
+ /** appRefreshToken 数据库字段:app_refresh_token */
+ private String appRefreshToken;
}
diff --git a/sop-openapi/src/main/java/com/gitee/sop/openapi/po/AuthTokePo.java b/sop-openapi/src/main/java/com/gitee/sop/openapi/po/AuthTokePo.java
index 446dbcb8..e2d88e23 100644
--- a/sop-openapi/src/main/java/com/gitee/sop/openapi/po/AuthTokePo.java
+++ b/sop-openapi/src/main/java/com/gitee/sop/openapi/po/AuthTokePo.java
@@ -3,6 +3,7 @@ package com.gitee.sop.openapi.po;
import com.gitee.sop.servercommon.param.validation.Group1;
import com.gitee.sop.servercommon.param.validation.Group2;
import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
import org.hibernate.validator.constraints.Length;
import javax.validation.constraints.NotBlank;
@@ -11,6 +12,8 @@ import javax.validation.constraints.NotBlank;
*
* @author wangping created on 2020/11/2 18:31
*/
+
+@Data
public class AuthTokePo {
@@ -23,18 +26,14 @@ public class AuthTokePo {
@Length(min = 1, max = 64, message = "{isp.auth.app_id_length_error}=1,64", groups = Group2.class)
private String code;
- @NotBlank(message = "{isp.auth.user_token_empty_error}", groups = Group1.class)
- @Length(min = 1, max = 64, message = "{isp.auth.user_token_length_error}=1,64", groups = Group2.class)
- @ApiModelProperty(value = "用户登录凭证", required = true, example = "1111", position = 2)
- private String grant_type;
-
-
/**
* 授权类型。
* 如果使用app_auth_code换取token,则为authorization_code,
* 如果使用refresh_token换取新的token,则为refresh_token
*/
- @NotBlank(message = "授权类型不能为空")
+ @NotBlank(message = "{isp.auth.user_token_empty_error}", groups = Group1.class)
+ @Length(min = 1, max = 64, message = "{isp.auth.user_token_length_error}=1,64", groups = Group2.class)
+ @ApiModelProperty(value = "授权类型不能为空", required = true, example = "1111", position = 2)
private String grantType;
diff --git a/sop-openapi/src/main/java/com/gitee/sop/openapi/service/AuthCodeService.java b/sop-openapi/src/main/java/com/gitee/sop/openapi/service/AuthCodeService.java
index 9bb753b4..b904028c 100644
--- a/sop-openapi/src/main/java/com/gitee/sop/openapi/service/AuthCodeService.java
+++ b/sop-openapi/src/main/java/com/gitee/sop/openapi/service/AuthCodeService.java
@@ -1,5 +1,6 @@
package com.gitee.sop.openapi.service;
+import com.alibaba.fastjson.JSONObject;
import com.gitee.fastmybatis.core.query.Query;
import com.gitee.sop.openapi.config.RedisOperator;
import com.gitee.sop.openapi.entity.IsvAuthTokenEntity;
@@ -13,6 +14,7 @@ import com.gitee.sop.openapi.util.RedisKeyUtil;
import com.gitee.sop.servercommon.exception.ServiceException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
/***
*
@@ -20,16 +22,7 @@ import org.springframework.stereotype.Service;
*/
@Slf4j
@Service
-public class AuthCodeService {
- public static final int FORBIDDEN = 2;
-
- /** 0 插件应用未授权 **/
- public static final int UNAUTHORIZED = 0;
- /** 1 插件应用已授权 **/
- public static final int AUTHORIZED = 1;
-
- public static final Byte ENABLE_TOKEN = 1;
- public static final Byte DISABLE_TOKEN = 0;
+public class AuthCodeService implements AuthService {
private final IsvInfoMapper isvInfoMapper;
private final IsvAuthTokenMapper isvAuthTokenMapper;
@@ -43,6 +36,8 @@ public class AuthCodeService {
this.redisOperator = redisOperator;
}
+
+ @Transactional
public AuthCodeVo getCode(AuthCodePo authCodePo) {
IsvInfoEntity isvInfo = isvInfoMapper.getByColumn("app_key", authCodePo.getAppId());
@@ -51,8 +46,6 @@ public class AuthCodeService {
throw new ServiceException("应用ID未申请或已被禁用");
}
- // todo check userToken and get userId
-
String authCode = MD5GeneratorUtil.generateValue();
Query query = new Query()
@@ -65,23 +58,28 @@ public class AuthCodeService {
if (authTokenEntity == null) {
authCodeVo.setState(UNAUTHORIZED);
authTokenEntity = new IsvAuthTokenEntity();
- authTokenEntity.setAppAuthToken(authCode);
+ authTokenEntity.setAppAuthCode(authCode);
authTokenEntity.setAppKey(authCodePo.getAppId());
authTokenEntity.setUserId(authCodePo.getUserId());
isvAuthTokenMapper.save(authTokenEntity);
} else {
- authCodeVo.setState(AUTHORIZED);
+ authTokenEntity.setAppAuthCode(authCode);
isvAuthTokenMapper.update(authTokenEntity);
}
// 写入redis缓存
- String codeKey = RedisKeyUtil.getCodeKey(authCodePo.getAppId(), authCodePo.getUserId());
- redisOperator.set(codeKey, authCodePo.getUserId());
+ try {
+ String codeKey = RedisKeyUtil.getCodeKey(authCode);
+ redisOperator.set(codeKey, JSONObject.toJSON(authCodePo), CODE_TIMEOUT);
+ } catch (Exception e) {
+ throw new ServiceException("获取code失败");
+ }
return authCodeVo;
}
+ @Transactional
public void cancelToken(Long userId) {
// todo check userToken and get userId
@@ -94,13 +92,21 @@ public class AuthCodeService {
throw new ServiceException("用户未授权插件应用");
}
- authTokenEntity.setStatus(ENABLE_TOKEN);
- isvAuthTokenMapper.update(authTokenEntity);
+ try {
+ authTokenEntity.setStatus(ENABLE_TOKEN);
+ isvAuthTokenMapper.update(authTokenEntity);
+ } catch (Exception e) {
+ throw new ServiceException("解除授权失败,系统忙,请稍后!");
+ }
- String tokenKey = RedisKeyUtil.getAuthTokenKey(authTokenEntity.getAppKey(), authTokenEntity.getUserId());
- String refreshKey = RedisKeyUtil.getRefreshTokenKey(authTokenEntity.getAppKey(), authTokenEntity.getUserId());
- redisOperator.del(tokenKey);
- redisOperator.del(refreshKey);
+ String tokenKey = RedisKeyUtil.getAuthTokenKey(authTokenEntity.getAppAuthToken());
+ String refreshKey = RedisKeyUtil.getRefreshTokenKey(authTokenEntity.getAppRefreshToken());
+ try {
+ redisOperator.del(tokenKey);
+ redisOperator.del(refreshKey);
+ } catch (Exception e) {
+ throw new ServiceException("解除授权失败,系统忙,请稍后!");
+ }
}
}
diff --git a/sop-openapi/src/main/java/com/gitee/sop/openapi/service/AuthService.java b/sop-openapi/src/main/java/com/gitee/sop/openapi/service/AuthService.java
new file mode 100644
index 00000000..28102e8b
--- /dev/null
+++ b/sop-openapi/src/main/java/com/gitee/sop/openapi/service/AuthService.java
@@ -0,0 +1,20 @@
+package com.gitee.sop.openapi.service;
+
+/***
+ *
+ * @author wangping created on 2020/11/4 15:41
+ */
+public interface AuthService {
+
+ int FORBIDDEN = 2;
+
+ /** 0 插件应用未授权 **/
+ int UNAUTHORIZED = 0;
+ /** 1 插件应用已授权 **/
+ int AUTHORIZED = 1;
+
+ Byte ENABLE_TOKEN = 1;
+ Byte DISABLE_TOKEN = 0;
+
+ Long CODE_TIMEOUT = 3600L;
+}
diff --git a/sop-openapi/src/main/java/com/gitee/sop/openapi/service/AuthTokenService.java b/sop-openapi/src/main/java/com/gitee/sop/openapi/service/AuthTokenService.java
new file mode 100644
index 00000000..ca8d13f1
--- /dev/null
+++ b/sop-openapi/src/main/java/com/gitee/sop/openapi/service/AuthTokenService.java
@@ -0,0 +1,83 @@
+package com.gitee.sop.openapi.service;
+
+import com.alibaba.fastjson.JSONObject;
+import com.gitee.sop.openapi.config.RedisOperator;
+import com.gitee.sop.openapi.entity.IsvAuthTokenEntity;
+import com.gitee.sop.openapi.mapper.IsvAuthTokenMapper;
+import com.gitee.sop.openapi.po.AuthCodePo;
+import com.gitee.sop.openapi.po.AuthTokePo;
+import com.gitee.sop.openapi.util.GrantType;
+import com.gitee.sop.openapi.util.MD5GeneratorUtil;
+import com.gitee.sop.openapi.util.RedisKeyUtil;
+import com.gitee.sop.openapi.vo.AuthTokenVo;
+import com.gitee.sop.servercommon.exception.ServiceException;
+import org.springframework.stereotype.Service;
+
+/***
+ *
+ * @author wangping created on 2020/11/4 15:21
+ */
+@Service
+public class AuthTokenService implements AuthService {
+
+ private final RedisOperator redisOperator;
+ private final IsvAuthTokenMapper isvAuthTokenMapper;
+
+ public AuthTokenService(final RedisOperator redisOperator,
+ final IsvAuthTokenMapper isvAuthTokenMapper) {
+ this.redisOperator = redisOperator;
+ this.isvAuthTokenMapper = isvAuthTokenMapper;
+ }
+
+
+ public AuthTokenVo getToken(AuthTokePo authTokePo) {
+
+ AuthTokenVo tokenVo = new AuthTokenVo();
+ String grantType = authTokePo.getGrantType();
+ if (GrantType.AUTHORIZATION_CODE.name().equals(grantType)) {
+ String codeKey = RedisKeyUtil.getCodeKey(authTokePo.getCode());
+ Object jsonObj = redisOperator.get(codeKey);
+ if (jsonObj == null) {
+ throw new ServiceException("Invalid request");
+ }
+
+ AuthCodePo codePo = JSONObject.parseObject(jsonObj.toString(), AuthCodePo.class);
+ if (codePo == null) {
+ throw new ServiceException("Can not found user by code");
+ }
+ IsvAuthTokenEntity authTokenEntity = isvAuthTokenMapper.getByColumn("app_auth_code", authTokePo.getCode());
+ if (authTokenEntity == null) {
+ throw new ServiceException("Can not found user by code");
+ }
+
+
+ String authToken = MD5GeneratorUtil.generateValue();
+ String refreshToken = MD5GeneratorUtil.generateValue();
+
+
+ authTokenEntity.setStatus((byte) AUTHORIZED);
+ authTokenEntity.setAppAuthToken(authToken);
+ authTokenEntity.setAppRefreshToken(refreshToken);
+ isvAuthTokenMapper.update(authTokenEntity);
+
+ String authTokenKey = RedisKeyUtil.getAuthTokenKey(authToken);
+ String refreshTokenKey = RedisKeyUtil.getRefreshTokenKey(refreshToken);
+ redisOperator.set(authTokenKey, codePo);
+ redisOperator.set(refreshTokenKey, codePo);
+
+ tokenVo.setAppAuthToken(authToken);
+ tokenVo.setAppRefreshToken(refreshToken);
+ tokenVo.setUserId(codePo.getUserId());
+ return tokenVo;
+ } else if (GrantType.REFRESH_TOKEN.name().equals(grantType)) {
+
+
+ return tokenVo;
+ } else {
+ throw new ServiceException("Invalid grant");
+ }
+
+ }
+
+
+}
diff --git a/sop-openapi/src/main/java/com/gitee/sop/openapi/util/GrantType.java b/sop-openapi/src/main/java/com/gitee/sop/openapi/util/GrantType.java
new file mode 100644
index 00000000..de8949ee
--- /dev/null
+++ b/sop-openapi/src/main/java/com/gitee/sop/openapi/util/GrantType.java
@@ -0,0 +1,23 @@
+package com.gitee.sop.openapi.util;
+
+/***
+ *
+ * @author wangping created on 2020/11/4 15:25
+ */
+public enum GrantType {
+
+ AUTHORIZATION_CODE("authorization_code"),
+ PASSWORD("password"),
+ REFRESH_TOKEN("refresh_token"),
+ CLIENT_CREDENTIALS("client_credentials");
+
+ private String grantType;
+
+ private GrantType(String grantType) {
+ this.grantType = grantType;
+ }
+
+ public String toString() {
+ return this.grantType;
+ }
+}
diff --git a/sop-openapi/src/main/java/com/gitee/sop/openapi/util/RedisKeyUtil.java b/sop-openapi/src/main/java/com/gitee/sop/openapi/util/RedisKeyUtil.java
index 61ec6687..19bab21c 100644
--- a/sop-openapi/src/main/java/com/gitee/sop/openapi/util/RedisKeyUtil.java
+++ b/sop-openapi/src/main/java/com/gitee/sop/openapi/util/RedisKeyUtil.java
@@ -16,15 +16,15 @@ public class RedisKeyUtil {
private static final Joiner JOINER = Joiner.on(":");
- public static String getCodeKey(String appId, Long userId) {
- return JOINER.join(CODE_PREFIX, appId, userId);
+ public static String getCodeKey(String code) {
+ return JOINER.join(CODE_PREFIX, code);
}
- public static String getAuthTokenKey(String appId, Long userId) {
- return JOINER.join(AUTH_TOKEN_PREFIX, appId, userId);
+ public static String getAuthTokenKey(String token) {
+ return JOINER.join(AUTH_TOKEN_PREFIX, token);
}
- public static String getRefreshTokenKey(String appId, Long userId) {
- return JOINER.join(REFRESH_TOKEN_PREFIX, appId, userId);
+ public static String getRefreshTokenKey(String refreshToken) {
+ return JOINER.join(REFRESH_TOKEN_PREFIX, refreshToken);
}
}
diff --git a/sop-openapi/src/main/java/com/gitee/sop/openapi/vo/AuthTokenVo.java b/sop-openapi/src/main/java/com/gitee/sop/openapi/vo/AuthTokenVo.java
new file mode 100644
index 00000000..c8476430
--- /dev/null
+++ b/sop-openapi/src/main/java/com/gitee/sop/openapi/vo/AuthTokenVo.java
@@ -0,0 +1,40 @@
+package com.gitee.sop.openapi.vo;
+
+import lombok.Data;
+
+/***
+ *
+ * @author wangping created on 2020/11/4 15:22
+ */
+@Data
+public class AuthTokenVo {
+
+ /**
+ * 授权令牌
+ */
+ private String appAuthToken;
+
+ /**
+ * 用户id
+ */
+ private Long userId;
+
+
+ /**
+ * 令牌有效期. -1:永久有效
+ */
+ private long expiresIn = -1;
+
+ /**
+ * 刷新令牌有效期. -1:永久有效
+ */
+ private long reExpiresIn = -1;
+
+
+ /**
+ * 刷新令牌时使用。
+ * 刷新令牌后,我们会保证老的app_auth_token从刷新开始10分钟内可继续使用,请及时替换为最新token
+ */
+ private String appRefreshToken;
+
+}
diff --git a/sop-openapi/src/main/resources/application-standalone.yml b/sop-openapi/src/main/resources/application-standalone.yml
index 12b1ea14..89510048 100644
--- a/sop-openapi/src/main/resources/application-standalone.yml
+++ b/sop-openapi/src/main/resources/application-standalone.yml
@@ -1,6 +1,6 @@
spring:
redis:
- host: 10.0.0.39
+ host: localhost
port: 6379
jedis:
pool:
@@ -10,4 +10,4 @@ spring:
min-idle: 1
database: 0
timeout: 60000
- password: lt@3600
+ password:
diff --git a/sop-openapi/src/main/resources/application.properties b/sop-openapi/src/main/resources/application.properties
index 91aad173..b208c10a 100644
--- a/sop-openapi/src/main/resources/application.properties
+++ b/sop-openapi/src/main/resources/application.properties
@@ -1,6 +1,6 @@
spring.profiles.active=dev
server.port=8089
-spring.application.name=sop-openapi
+spring.application.name=open-apis
# ע
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
\ No newline at end of file