Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
zlt2000
microservices-platform
提交
d78ec64b
microservices-platform
项目概览
zlt2000
/
microservices-platform
9 个月 前同步成功
通知
16
Star
4
Fork
3
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
microservices-platform
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
提交
d78ec64b
编写于
7月 09, 2019
作者:
zlt2000
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
1.增加token自动续签功能(仅限于redis token模式),可配置化:开关、白名单、黑名单
2.项目默认token模式改为redis,并且开启自动续签功能
上级
f0c07434
变更
10
隐藏空白更改
内联
并排
Showing
10 changed file
with
170 addition
and
31 deletion
+170
-31
zlt-commons/zlt-auth-client-spring-boot-starter/src/main/java/com/central/oauth2/common/properties/AuthProperties.java
.../com/central/oauth2/common/properties/AuthProperties.java
+6
-1
zlt-commons/zlt-auth-client-spring-boot-starter/src/main/java/com/central/oauth2/common/properties/RenewProperties.java
...com/central/oauth2/common/properties/RenewProperties.java
+34
-0
zlt-commons/zlt-auth-client-spring-boot-starter/src/main/java/com/central/oauth2/common/service/impl/DefaultPermissionServiceImpl.java
...th2/common/service/impl/DefaultPermissionServiceImpl.java
+1
-1
zlt-commons/zlt-auth-client-spring-boot-starter/src/main/java/com/central/oauth2/common/store/AuthRedisTokenStore.java
.../com/central/oauth2/common/store/AuthRedisTokenStore.java
+6
-1
zlt-commons/zlt-auth-client-spring-boot-starter/src/main/java/com/central/oauth2/common/store/CustomRedisTokenStore.java
...om/central/oauth2/common/store/CustomRedisTokenStore.java
+100
-11
zlt-commons/zlt-common-spring-boot-starter/src/main/java/com/central/common/constant/SecurityConstants.java
...n/java/com/central/common/constant/SecurityConstants.java
+4
-0
zlt-doc/sql/oauth-center.sql
zlt-doc/sql/oauth-center.sql
+4
-4
zlt-gateway/zuul-gateway/src/main/resources/application.yml
zlt-gateway/zuul-gateway/src/main/resources/application.yml
+8
-1
zlt-uaa/src/main/java/com/central/oauth/controller/OAuth2Controller.java
...n/java/com/central/oauth/controller/OAuth2Controller.java
+6
-11
zlt-uaa/src/main/resources/application.yml
zlt-uaa/src/main/resources/application.yml
+1
-1
未找到文件。
zlt-commons/zlt-auth-client-spring-boot-starter/src/main/java/com/central/oauth2/common/properties/AuthProperties.java
浏览文件 @
d78ec64b
...
...
@@ -19,5 +19,10 @@ public class AuthProperties {
/**
* 是否开启url权限验证
*/
private
boolean
urlEnabled
=
false
;
private
Boolean
urlEnabled
=
false
;
/**
* token自动续签配置(目前只有redis实现)
*/
private
RenewProperties
renew
=
new
RenewProperties
();
}
zlt-commons/zlt-auth-client-spring-boot-starter/src/main/java/com/central/oauth2/common/properties/RenewProperties.java
0 → 100644
浏览文件 @
d78ec64b
package
com.central.oauth2.common.properties
;
import
lombok.Getter
;
import
lombok.Setter
;
import
java.util.ArrayList
;
import
java.util.List
;
/**
* 续签配置
*
* @author zlt
* @date 2019/7/9
*/
@Setter
@Getter
public
class
RenewProperties
{
/**
* 是否开启token自动续签(目前只有redis实现)
*/
private
Boolean
enable
=
false
;
/**
* 白名单,配置需要自动续签的应用id(与黑名单互斥,只能配置其中一个),不配置默认所有应用都生效
* 配置enable为true时才生效
*/
private
List
<
String
>
includeClientIds
=
new
ArrayList
<>();
/**
* 黑名单,配置不需要自动续签的应用id(与白名单互斥,只能配置其中一个)
* 配置enable为true时才生效
*/
private
List
<
String
>
exclusiveClientIds
=
new
ArrayList
<>();
}
zlt-commons/zlt-auth-client-spring-boot-starter/src/main/java/com/central/oauth2/common/service/impl/DefaultPermissionServiceImpl.java
浏览文件 @
d78ec64b
...
...
@@ -49,7 +49,7 @@ public abstract class DefaultPermissionServiceImpl implements IPermissionService
}
if
(!(
authentication
instanceof
AnonymousAuthenticationToken
))
{
//判断是否开启url权限验证
if
(!
securityProperties
.
getAuth
().
is
UrlEnabled
())
{
if
(!
securityProperties
.
getAuth
().
get
UrlEnabled
())
{
return
true
;
}
//超级管理员admin不需认证
...
...
zlt-commons/zlt-auth-client-spring-boot-starter/src/main/java/com/central/oauth2/common/store/AuthRedisTokenStore.java
浏览文件 @
d78ec64b
package
com.central.oauth2.common.store
;
import
com.central.oauth2.common.properties.SecurityProperties
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.data.redis.connection.RedisConnectionFactory
;
import
org.springframework.security.oauth2.provider.ClientDetailsService
;
import
org.springframework.security.oauth2.provider.token.TokenStore
;
/**
...
...
@@ -16,8 +18,11 @@ public class AuthRedisTokenStore {
@Autowired
private
RedisConnectionFactory
connectionFactory
;
@Autowired
private
SecurityProperties
securityProperties
;
@Bean
public
TokenStore
tokenStore
()
{
return
new
CustomRedisTokenStore
(
connectionFactory
);
return
new
CustomRedisTokenStore
(
connectionFactory
,
securityProperties
);
}
}
zlt-commons/zlt-auth-client-spring-boot-starter/src/main/java/com/central/oauth2/common/store/CustomRedisTokenStore.java
浏览文件 @
d78ec64b
package
com.central.oauth2.common.store
;
import
com.central.common.constant.SecurityConstants
;
import
com.central.oauth2.common.properties.SecurityProperties
;
import
org.springframework.data.redis.connection.RedisClusterConnection
;
import
org.springframework.data.redis.connection.RedisConnection
;
import
org.springframework.data.redis.connection.RedisConnectionFactory
;
import
org.springframework.data.redis.core.Cursor
;
import
org.springframework.data.redis.core.ScanOptions
;
import
org.springframework.security.oauth2.common.DefaultOAuth2AccessToken
;
import
org.springframework.security.oauth2.common.ExpiringOAuth2RefreshToken
;
import
org.springframework.security.oauth2.common.OAuth2AccessToken
;
import
org.springframework.security.oauth2.common.OAuth2RefreshToken
;
import
org.springframework.security.oauth2.provider.ClientDetails
;
import
org.springframework.security.oauth2.provider.OAuth2Authentication
;
import
org.springframework.security.oauth2.provider.OAuth2Request
;
import
org.springframework.security.oauth2.provider.token.AuthenticationKeyGenerator
;
import
org.springframework.security.oauth2.provider.token.DefaultAuthenticationKeyGenerator
;
import
org.springframework.security.oauth2.provider.token.TokenStore
;
...
...
@@ -30,6 +35,7 @@ import java.util.List;
* 1. 支持redis cluster模式
* 2. 非cluster模式时使用pipeline减少连接次数
* 3. CLIENT_ID_TO_ACCESS集合改为list,方便业务顺序遍历
* 4. 自动续签token(可配置是否开启)
*
* @author zlt
* @date 2019/7/7
...
...
@@ -44,6 +50,10 @@ public class CustomRedisTokenStore implements TokenStore {
private
static
final
String
REFRESH_TO_ACCESS
=
"refresh_to_access:"
;
private
static
final
String
CLIENT_ID_TO_ACCESS
=
"client_id_to_access:"
;
private
static
final
String
UNAME_TO_ACCESS
=
"uname_to_access:"
;
/**
* 续签时间比例,当前剩余时间小于小于过期总时长的50%则续签
*/
private
static
final
Double
RENEW_RATIO
=
0.5
;
private
static
final
boolean
springDataRedis_2_0
=
ClassUtils
.
isPresent
(
"org.springframework.data.redis.connection.RedisStandaloneConfiguration"
,
...
...
@@ -57,8 +67,14 @@ public class CustomRedisTokenStore implements TokenStore {
private
Method
redisConnectionSet_2_0
;
public
CustomRedisTokenStore
(
RedisConnectionFactory
connectionFactory
)
{
/**
* 认证配置
*/
private
SecurityProperties
securityProperties
;
public
CustomRedisTokenStore
(
RedisConnectionFactory
connectionFactory
,
SecurityProperties
securityProperties
)
{
this
.
connectionFactory
=
connectionFactory
;
this
.
securityProperties
=
securityProperties
;
if
(
springDataRedis_2_0
)
{
this
.
loadRedisConnectionMethods_2_0
();
}
...
...
@@ -105,6 +121,10 @@ public class CustomRedisTokenStore implements TokenStore {
return
serializationStrategy
.
deserialize
(
bytes
,
OAuth2RefreshToken
.
class
);
}
private
ClientDetails
deserializeClientDetails
(
byte
[]
bytes
)
{
return
serializationStrategy
.
deserialize
(
bytes
,
ClientDetails
.
class
);
}
private
byte
[]
serialize
(
String
string
)
{
return
serializationStrategy
.
serialize
(
string
);
}
...
...
@@ -140,7 +160,68 @@ public class CustomRedisTokenStore implements TokenStore {
@Override
public
OAuth2Authentication
readAuthentication
(
OAuth2AccessToken
token
)
{
return
readAuthentication
(
token
.
getValue
());
OAuth2Authentication
auth2Authentication
=
readAuthentication
(
token
.
getValue
());
//是否开启token续签
boolean
isRenew
=
securityProperties
.
getAuth
().
getRenew
().
getEnable
();
if
(
isRenew
&&
auth2Authentication
!=
null
)
{
OAuth2Request
clientAuth
=
auth2Authentication
.
getOAuth2Request
();
//判断当前应用是否需要自动续签
if
(
checkRenewClientId
(
clientAuth
.
getClientId
()))
{
//获取过期时长
int
validitySeconds
=
getAccessTokenValiditySeconds
(
clientAuth
.
getClientId
());
if
(
validitySeconds
>
0
)
{
int
expiresIn
=
token
.
getExpiresIn
();
double
expiresRatio
=
expiresIn
/
(
double
)
validitySeconds
;
//判断是否需要续签,当前剩余时间小于过期时长的50%则续签
if
(
expiresRatio
<=
RENEW_RATIO
)
{
//更新AccessToken过期时间
DefaultOAuth2AccessToken
oAuth2AccessToken
=
(
DefaultOAuth2AccessToken
)
token
;
oAuth2AccessToken
.
setExpiration
(
new
Date
(
System
.
currentTimeMillis
()
+
(
validitySeconds
*
1000L
)));
storeAccessToken
(
oAuth2AccessToken
,
auth2Authentication
,
true
);
}
}
}
}
return
auth2Authentication
;
}
/**
* 判断应用自动续签是否满足白名单和黑名单的过滤逻辑
* @param clientId 应用id
* @return 是否满足
*/
private
boolean
checkRenewClientId
(
String
clientId
)
{
boolean
result
=
true
;
//白名单
List
<
String
>
includeClientIds
=
securityProperties
.
getAuth
().
getRenew
().
getIncludeClientIds
();
//黑名单
List
<
String
>
exclusiveClientIds
=
securityProperties
.
getAuth
().
getRenew
().
getExclusiveClientIds
();
if
(
includeClientIds
.
size
()
>
0
)
{
result
=
includeClientIds
.
contains
(
clientId
);
}
else
if
(
exclusiveClientIds
.
size
()
>
0
)
{
result
=
!
exclusiveClientIds
.
contains
(
clientId
);
}
return
result
;
}
/**
* 获取token的总有效时长
* @param clientId 应用id
*/
private
int
getAccessTokenValiditySeconds
(
String
clientId
)
{
RedisConnection
conn
=
getConnection
();
byte
[]
bytes
;
try
{
bytes
=
conn
.
get
(
serializeKey
(
SecurityConstants
.
CACHE_CLIENT_KEY
+
":"
+
clientId
));
}
finally
{
conn
.
close
();
}
ClientDetails
clientDetails
=
deserializeClientDetails
(
bytes
);
if
(
clientDetails
!=
null
&&
clientDetails
.
getAccessTokenValiditySeconds
()
!=
null
)
{
return
clientDetails
.
getAccessTokenValiditySeconds
();
}
//返回默认值
return
SecurityConstants
.
ACCESS_TOKEN_VALIDITY_SECONDS
;
}
@Override
...
...
@@ -152,8 +233,7 @@ public class CustomRedisTokenStore implements TokenStore {
}
finally
{
conn
.
close
();
}
OAuth2Authentication
auth
=
deserializeAuthentication
(
bytes
);
return
auth
;
return
deserializeAuthentication
(
bytes
);
}
@Override
...
...
@@ -165,8 +245,7 @@ public class CustomRedisTokenStore implements TokenStore {
RedisConnection
conn
=
getConnection
();
try
{
byte
[]
bytes
=
conn
.
get
(
serializeKey
(
REFRESH_AUTH
+
token
));
OAuth2Authentication
auth
=
deserializeAuthentication
(
bytes
);
return
auth
;
return
deserializeAuthentication
(
bytes
);
}
finally
{
conn
.
close
();
}
...
...
@@ -174,6 +253,14 @@ public class CustomRedisTokenStore implements TokenStore {
@Override
public
void
storeAccessToken
(
OAuth2AccessToken
token
,
OAuth2Authentication
authentication
)
{
storeAccessToken
(
token
,
authentication
,
false
);
}
/**
* 存储token
* @param isExpire 是否刷新过期时间
*/
private
void
storeAccessToken
(
OAuth2AccessToken
token
,
OAuth2Authentication
authentication
,
boolean
isExpire
)
{
byte
[]
serializedAccessToken
=
serialize
(
token
);
byte
[]
serializedAuth
=
serialize
(
authentication
);
byte
[]
accessKey
=
serializeKey
(
ACCESS
+
token
.
getValue
());
...
...
@@ -198,10 +285,13 @@ public class CustomRedisTokenStore implements TokenStore {
conn
.
set
(
authKey
,
serializedAuth
);
conn
.
set
(
authToAccessKey
,
serializedAccessToken
);
}
if
(!
authentication
.
isClientOnly
())
{
conn
.
sAdd
(
approvalKey
,
serializedAccessToken
);
//如果是刷新token过期时间,不需要再往集合添加token
if
(!
isExpire
)
{
if
(!
authentication
.
isClientOnly
())
{
conn
.
sAdd
(
approvalKey
,
serializedAccessToken
);
}
conn
.
rPush
(
clientId
,
serializedAccessToken
);
}
conn
.
rPush
(
clientId
,
serializedAccessToken
);
if
(
token
.
getExpiration
()
!=
null
)
{
int
seconds
=
token
.
getExpiresIn
();
conn
.
expire
(
accessKey
,
seconds
);
...
...
@@ -345,8 +435,7 @@ public class CustomRedisTokenStore implements TokenStore {
}
finally
{
conn
.
close
();
}
OAuth2RefreshToken
refreshToken
=
deserializeRefreshToken
(
bytes
);
return
refreshToken
;
return
deserializeRefreshToken
(
bytes
);
}
@Override
...
...
zlt-commons/zlt-common-spring-boot-starter/src/main/java/com/central/common/constant/SecurityConstants.java
浏览文件 @
d78ec64b
...
...
@@ -136,4 +136,8 @@ public interface SecurityConstants {
* 登出URL
*/
String
LOGOUT_URL
=
"/oauth/remove/token"
;
/**
* 默认token过期时间(1小时)
*/
Integer
ACCESS_TOKEN_VALIDITY_SECONDS
=
60
*
60
;
}
zlt-doc/sql/oauth-center.sql
浏览文件 @
d78ec64b
...
...
@@ -27,7 +27,7 @@ CREATE TABLE `oauth_client_details` (
-- ----------------------------
-- Records of oauth_client_details
-- ----------------------------
INSERT
INTO
`oauth_client_details`
VALUES
(
1
,
'app'
,
NULL
,
'$2a$10$i3F515wEDiB4Gvj9ym9Prui0dasRttEUQ9ink4Wpgb4zEDCAlV8zO'
,
'app'
,
'app'
,
'password,refresh_token'
,
NULL
,
NULL
,
18000
,
NULL
,
'{}'
,
'true'
,
NULL
,
NULL
);
INSERT
INTO
`oauth_client_details`
VALUES
(
2
,
'mobile'
,
'mobile,test'
,
'$2a$10$ULxRssv/4NWOc388lZFbyus3IFfsbcpG/BZOq4TRxDhsx5HHIR7Jm'
,
'mobile'
,
'all'
,
'password,refresh_token'
,
NULL
,
NULL
,
18000
,
NULL
,
'{}'
,
'true'
,
NULL
,
NULL
);
INSERT
INTO
`oauth_client_details`
VALUES
(
4
,
'webApp'
,
NULL
,
'$2a$10$06msMGYRH8nrm4iVnKFNKOoddB8wOwymVhbUzw/d3ZixD7Nq8ot72'
,
'webApp'
,
'app'
,
'authorization_code,password,refresh_token,client_credentials'
,
NULL
,
NULL
,
18000
,
NULL
,
'{}'
,
'true'
,
NULL
,
NULL
);
INSERT
INTO
`oauth_client_details`
VALUES
(
11
,
'zlt'
,
NULL
,
'$2a$10$/o.wuORzVcXaezmYVzwYMuoY7qeWXBALwQmkskXD/7C6rqfCyPrna'
,
'zlt'
,
'all'
,
'authorization_code,password,refresh_token,client_credentials'
,
'http://127.0.0.1:8080/singleLogin'
,
NULL
,
18000
,
28800
,
'{}'
,
'true'
,
'2018-12-27 00:50:30'
,
'2018-12-27 00:50:30'
);
\ No newline at end of file
INSERT
INTO
`oauth_client_details`
VALUES
(
1
,
'app'
,
NULL
,
'$2a$10$i3F515wEDiB4Gvj9ym9Prui0dasRttEUQ9ink4Wpgb4zEDCAlV8zO'
,
'app'
,
'app'
,
'password,refresh_token'
,
NULL
,
NULL
,
3600
,
NULL
,
'{}'
,
'true'
,
NULL
,
NULL
);
INSERT
INTO
`oauth_client_details`
VALUES
(
2
,
'mobile'
,
'mobile,test'
,
'$2a$10$ULxRssv/4NWOc388lZFbyus3IFfsbcpG/BZOq4TRxDhsx5HHIR7Jm'
,
'mobile'
,
'all'
,
'password,refresh_token'
,
NULL
,
NULL
,
3600
,
NULL
,
'{}'
,
'true'
,
NULL
,
NULL
);
INSERT
INTO
`oauth_client_details`
VALUES
(
4
,
'webApp'
,
NULL
,
'$2a$10$06msMGYRH8nrm4iVnKFNKOoddB8wOwymVhbUzw/d3ZixD7Nq8ot72'
,
'webApp'
,
'app'
,
'authorization_code,password,refresh_token,client_credentials'
,
NULL
,
NULL
,
3600
,
NULL
,
'{}'
,
'true'
,
NULL
,
NULL
);
INSERT
INTO
`oauth_client_details`
VALUES
(
11
,
'zlt'
,
NULL
,
'$2a$10$/o.wuORzVcXaezmYVzwYMuoY7qeWXBALwQmkskXD/7C6rqfCyPrna'
,
'zlt'
,
'all'
,
'authorization_code,password,refresh_token,client_credentials'
,
'http://127.0.0.1:8080/singleLogin'
,
NULL
,
3600
,
28800
,
'{}'
,
'true'
,
'2018-12-27 00:50:30'
,
'2018-12-27 00:50:30'
);
\ No newline at end of file
zlt-gateway/zuul-gateway/src/main/resources/application.yml
浏览文件 @
d78ec64b
...
...
@@ -29,7 +29,7 @@ zlt:
oauth2
:
token
:
store
:
type
:
re
sJwt
type
:
re
dis
security
:
ignore
:
# 忽略认证的地址
...
...
@@ -45,6 +45,13 @@ zlt:
httpUrls
:
/api-uaa/clients/**
#是否开启url级别权限
urlEnabled
:
false
renew
:
#是否开启token自动续签(目前只有redis实现)
enable
:
true
#白名单
includeClientIds
:
-
webApp
zuul
:
ribbon-isolation-strategy
:
thread
...
...
zlt-uaa/src/main/java/com/central/oauth/controller/OAuth2Controller.java
浏览文件 @
d78ec64b
...
...
@@ -2,10 +2,8 @@ package com.central.oauth.controller;
import
com.central.common.constant.SecurityConstants
;
import
com.central.common.model.Result
;
import
com.central.common.utils.SpringUtil
;
import
com.central.oauth.mobile.MobileAuthenticationToken
;
import
com.central.oauth.openid.OpenIdAuthenticationToken
;
import
com.central.oauth.service.impl.RedisClientDetailsService
;
import
com.central.oauth2.common.util.AuthUtils
;
import
com.fasterxml.jackson.databind.ObjectMapper
;
import
io.swagger.annotations.Api
;
...
...
@@ -22,10 +20,7 @@ import org.springframework.security.core.context.SecurityContextHolder;
import
org.springframework.security.crypto.password.PasswordEncoder
;
import
org.springframework.security.oauth2.common.OAuth2AccessToken
;
import
org.springframework.security.oauth2.common.exceptions.UnapprovedClientAuthenticationException
;
import
org.springframework.security.oauth2.provider.ClientDetails
;
import
org.springframework.security.oauth2.provider.OAuth2Authentication
;
import
org.springframework.security.oauth2.provider.OAuth2Request
;
import
org.springframework.security.oauth2.provider.TokenRequest
;
import
org.springframework.security.oauth2.provider.*
;
import
org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices
;
import
org.springframework.web.bind.annotation.PostMapping
;
import
org.springframework.web.bind.annotation.RestController
;
...
...
@@ -57,6 +52,9 @@ public class OAuth2Controller {
@Autowired
private
AuthenticationManager
authenticationManager
;
@Autowired
private
ClientDetailsService
clientDetailsService
;
@ApiOperation
(
value
=
"用户名密码获取token"
)
@PostMapping
(
SecurityConstants
.
PASSWORD_LOGIN_PRO_URL
)
public
void
getUserTokenInfo
(
...
...
@@ -93,7 +91,7 @@ public class OAuth2Controller {
String
clientId
=
clientInfos
[
0
];
String
clientSecret
=
clientInfos
[
1
];
ClientDetails
clientDetails
=
getClient
(
clientId
,
clientSecret
,
null
);
ClientDetails
clientDetails
=
getClient
(
clientId
,
clientSecret
);
TokenRequest
tokenRequest
=
new
TokenRequest
(
MapUtils
.
EMPTY_MAP
,
clientId
,
clientDetails
.
getScope
(),
"customer"
);
OAuth2Request
oAuth2Request
=
tokenRequest
.
createOAuth2Request
(
clientDetails
);
Authentication
authentication
=
authenticationManager
.
authenticate
(
token
);
...
...
@@ -129,10 +127,7 @@ public class OAuth2Controller {
}
}
private
ClientDetails
getClient
(
String
clientId
,
String
clientSecret
,
RedisClientDetailsService
clientDetailsService
)
{
if
(
clientDetailsService
==
null
)
{
clientDetailsService
=
SpringUtil
.
getBean
(
RedisClientDetailsService
.
class
);
}
private
ClientDetails
getClient
(
String
clientId
,
String
clientSecret
)
{
ClientDetails
clientDetails
=
clientDetailsService
.
loadClientByClientId
(
clientId
);
if
(
clientDetails
==
null
)
{
...
...
zlt-uaa/src/main/resources/application.yml
浏览文件 @
d78ec64b
...
...
@@ -17,7 +17,7 @@ zlt:
oauth2
:
token
:
store
:
type
:
authJwt
type
:
redis
swagger
:
enabled
:
true
title
:
认证中心
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录