feat: 开放平台获取token接口

pull/7/head
wangping 5 years ago
parent 91b924bdc1
commit 21b03137d1
  1. 10
      sop-gateway/pom.xml
  2. 33
      sop-gateway/src/main/java/com/gitee/sop/gateway/config/MyConfig.java
  3. 12
      sop-gateway/src/main/resources/application-dev.properties
  4. 7
      sop-openapi/pom.xml
  5. 8
      sop-openapi/src/main/java/com/gitee/sop/openapi/SopOpenapiApplication.java
  6. 6
      sop-openapi/src/main/java/com/gitee/sop/openapi/entity/IsvAuthTokenEntity.java
  7. 13
      sop-openapi/src/main/java/com/gitee/sop/openapi/po/AuthTokePo.java
  8. 50
      sop-openapi/src/main/java/com/gitee/sop/openapi/service/AuthCodeService.java
  9. 20
      sop-openapi/src/main/java/com/gitee/sop/openapi/service/AuthService.java
  10. 83
      sop-openapi/src/main/java/com/gitee/sop/openapi/service/AuthTokenService.java
  11. 23
      sop-openapi/src/main/java/com/gitee/sop/openapi/util/GrantType.java
  12. 12
      sop-openapi/src/main/java/com/gitee/sop/openapi/util/RedisKeyUtil.java
  13. 40
      sop-openapi/src/main/java/com/gitee/sop/openapi/vo/AuthTokenVo.java
  14. 4
      sop-openapi/src/main/resources/application-standalone.yml
  15. 2
      sop-openapi/src/main/resources/application.properties

@ -67,6 +67,16 @@
<version>1.18.4</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- redis 依赖commons-pool -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
</dependencies>

@ -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;
}
});
}
}

@ -13,4 +13,14 @@ register.url=127.0.0.1:8848
# 如果需要传输大文本可以把值设置高一点
spring.codec.max-in-memory-size=262144
logging.level.com.gitee=debug
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=

@ -80,6 +80,13 @@
<groupId>net.oschina.durcframework</groupId>
<artifactId>fastmybatis-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.4</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>

@ -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);
}
}

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

@ -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;
/**
* 授权类型<br>
* 如果使用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;

@ -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("解除授权失败,系统忙,请稍后!");
}
}
}

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

@ -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");
}
}
}

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

@ -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);
}
}

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

@ -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:

@ -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
Loading…
Cancel
Save