Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
zlt2000
microservices-platform
提交
0a5fdf63
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 搜索 >>
提交
0a5fdf63
编写于
3月 17, 2022
作者:
L
lpphan
提交者:
晴天丶en
3月 17, 2022
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
过期key监听器
上级
4224ca83
变更
5
显示空白变更内容
内联
并排
Showing
5 changed file
with
174 addition
and
3 deletion
+174
-3
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
+13
-3
zlt-commons/zlt-common-core/src/main/java/com/central/common/constant/SecurityConstants.java
...n/java/com/central/common/constant/SecurityConstants.java
+4
-0
zlt-commons/zlt-redis-spring-boot-starter/src/main/java/com/central/common/redis/template/RedisRepository.java
...va/com/central/common/redis/template/RedisRepository.java
+22
-0
zlt-uaa/src/main/java/com/central/oauth/config/RedisListenerConfig.java
...in/java/com/central/oauth/config/RedisListenerConfig.java
+24
-0
zlt-uaa/src/main/java/com/central/oauth/listener/RedisKeyExpirationListener.java
...om/central/oauth/listener/RedisKeyExpirationListener.java
+111
-0
未找到文件。
zlt-commons/zlt-auth-client-spring-boot-starter/src/main/java/com/central/oauth2/common/store/CustomRedisTokenStore.java
浏览文件 @
0a5fdf63
...
...
@@ -39,6 +39,7 @@ import java.util.List;
*/
public
class
CustomRedisTokenStore
implements
TokenStore
{
private
static
final
String
ACCESS
=
"access:"
;
private
static
final
String
ACCESS_BAK
=
"access_bak:"
;
private
static
final
String
AUTH_TO_ACCESS
=
"auth_to_access:"
;
private
static
final
String
REFRESH_AUTH
=
"refresh_auth:"
;
private
static
final
String
ACCESS_TO_REFRESH
=
"access_to_refresh:"
;
...
...
@@ -118,7 +119,7 @@ public class CustomRedisTokenStore implements TokenStore {
}
private
ClientDetails
deserializeClientDetails
(
byte
[]
bytes
)
{
return
(
ClientDetails
)
redisValueSerializer
.
deserialize
(
bytes
);
return
(
ClientDetails
)
redisValueSerializer
.
deserialize
(
bytes
);
}
private
byte
[]
serialize
(
String
string
)
{
...
...
@@ -166,7 +167,7 @@ public class CustomRedisTokenStore implements TokenStore {
//获取过期时长
int
validitySeconds
=
getAccessTokenValiditySeconds
(
clientAuth
.
getClientId
());
if
(
validitySeconds
>
0
)
{
double
expiresRatio
=
token
.
getExpiresIn
()
/
(
double
)
validitySeconds
;
double
expiresRatio
=
token
.
getExpiresIn
()
/
(
double
)
validitySeconds
;
//判断是否需要续签,当前剩余时间小于过期时长的50%则续签
if
(
expiresRatio
<=
securityProperties
.
getAuth
().
getRenew
().
getTimeRatio
())
{
//更新AccessToken过期时间
...
...
@@ -182,6 +183,7 @@ public class CustomRedisTokenStore implements TokenStore {
/**
* 判断应用自动续签是否满足白名单和黑名单的过滤逻辑
*
* @param clientId 应用id
* @return 是否满足
*/
...
...
@@ -193,7 +195,7 @@ public class CustomRedisTokenStore implements TokenStore {
List
<
String
>
exclusiveClientIds
=
securityProperties
.
getAuth
().
getRenew
().
getExclusiveClientIds
();
if
(
includeClientIds
.
size
()
>
0
)
{
result
=
includeClientIds
.
contains
(
clientId
);
}
else
if
(
exclusiveClientIds
.
size
()
>
0
)
{
}
else
if
(
exclusiveClientIds
.
size
()
>
0
)
{
result
=
!
exclusiveClientIds
.
contains
(
clientId
);
}
return
result
;
...
...
@@ -201,6 +203,7 @@ public class CustomRedisTokenStore implements TokenStore {
/**
* 获取token的总有效时长
*
* @param clientId 应用id
*/
private
int
getAccessTokenValiditySeconds
(
String
clientId
)
{
...
...
@@ -256,12 +259,14 @@ public class CustomRedisTokenStore implements TokenStore {
/**
* 存储token
*
* @param isRenew 是否续签
*/
private
void
storeAccessToken
(
OAuth2AccessToken
token
,
OAuth2Authentication
authentication
,
boolean
isRenew
)
{
byte
[]
serializedAccessToken
=
serialize
(
token
);
byte
[]
serializedAuth
=
serialize
(
authentication
);
byte
[]
accessKey
=
serializeKey
(
ACCESS
+
token
.
getValue
());
byte
[]
accessBakKey
=
serializeKey
(
ACCESS_BAK
+
token
.
getValue
());
byte
[]
authKey
=
serializeKey
(
SecurityConstants
.
REDIS_TOKEN_AUTH
+
token
.
getValue
());
byte
[]
authToAccessKey
=
serializeKey
(
AUTH_TO_ACCESS
+
authenticationKeyGenerator
.
extractKey
(
authentication
));
byte
[]
approvalKey
=
serializeKey
(
SecurityConstants
.
REDIS_UNAME_TO_ACCESS
+
getApprovalKey
(
authentication
));
...
...
@@ -279,6 +284,7 @@ public class CustomRedisTokenStore implements TokenStore {
if
(
springDataRedis_2_0
)
{
try
{
this
.
redisConnectionSet_2_0
.
invoke
(
conn
,
accessKey
,
serializedAccessToken
);
this
.
redisConnectionSet_2_0
.
invoke
(
conn
,
accessBakKey
,
serializedAccessToken
);
this
.
redisConnectionSet_2_0
.
invoke
(
conn
,
authKey
,
serializedAuth
);
this
.
redisConnectionSet_2_0
.
invoke
(
conn
,
authToAccessKey
,
serializedAccessToken
);
}
catch
(
Exception
ex
)
{
...
...
@@ -286,6 +292,7 @@ public class CustomRedisTokenStore implements TokenStore {
}
}
else
{
conn
.
set
(
accessKey
,
serializedAccessToken
);
conn
.
set
(
accessBakKey
,
serializedAccessToken
);
conn
.
set
(
authKey
,
serializedAuth
);
conn
.
set
(
authToAccessKey
,
serializedAccessToken
);
}
...
...
@@ -303,6 +310,7 @@ public class CustomRedisTokenStore implements TokenStore {
if
(
token
.
getExpiration
()
!=
null
)
{
int
seconds
=
token
.
getExpiresIn
();
conn
.
expire
(
accessKey
,
seconds
);
conn
.
expire
(
accessBakKey
,
seconds
+
60
);
conn
.
expire
(
authKey
,
seconds
);
conn
.
expire
(
authToAccessKey
,
seconds
);
conn
.
expire
(
clientId
,
seconds
);
...
...
@@ -363,6 +371,7 @@ public class CustomRedisTokenStore implements TokenStore {
public
void
removeAccessToken
(
String
tokenValue
)
{
byte
[]
accessKey
=
serializeKey
(
ACCESS
+
tokenValue
);
byte
[]
accessBakKey
=
serializeKey
(
ACCESS_BAK
+
tokenValue
);
byte
[]
authKey
=
serializeKey
(
SecurityConstants
.
REDIS_TOKEN_AUTH
+
tokenValue
);
byte
[]
accessToRefreshKey
=
serializeKey
(
ACCESS_TO_REFRESH
+
tokenValue
);
RedisConnection
conn
=
getConnection
();
...
...
@@ -371,6 +380,7 @@ public class CustomRedisTokenStore implements TokenStore {
byte
[]
auth
=
conn
.
get
(
authKey
);
conn
.
openPipeline
();
conn
.
del
(
accessKey
);
conn
.
del
(
accessBakKey
);
conn
.
del
(
accessToRefreshKey
);
// Don't remove the refresh token - it's up to the caller to do that
conn
.
del
(
authKey
);
...
...
zlt-commons/zlt-common-core/src/main/java/com/central/common/constant/SecurityConstants.java
浏览文件 @
0a5fdf63
...
...
@@ -154,6 +154,10 @@ public interface SecurityConstants {
* redis中授权token对应的key
*/
String
REDIS_TOKEN_AUTH
=
"auth:"
;
/**
* 值同access 过期时间+60
*/
String
ACCESS_BAK
=
"access_bak:"
;
/**
* redis中应用对应的token集合的key
*/
...
...
zlt-commons/zlt-redis-spring-boot-starter/src/main/java/com/central/common/redis/template/RedisRepository.java
浏览文件 @
0a5fdf63
package
com.central.common.redis.template
;
import
lombok.extern.slf4j.Slf4j
;
import
org.apache.commons.lang3.StringUtils
;
import
org.springframework.dao.DataAccessException
;
import
org.springframework.data.redis.connection.RedisClusterNode
;
import
org.springframework.data.redis.connection.RedisConnection
;
...
...
@@ -178,6 +179,26 @@ public class RedisRepository {
public
Object
get
(
final
String
key
)
{
return
redisTemplate
.
opsForValue
().
get
(
key
);
}
/**
*获取原来key键对应的值并重新赋新值。
* @param key
* @param value
* @return
*/
public
String
getAndSet
(
final
String
key
,
Object
value
)
{
String
result
=
null
;
if
(
StringUtils
.
isEmpty
(
key
)){
log
.
error
(
"key不能为空"
);
return
null
;
}
try
{
result
=
(
String
)
redisTemplate
.
opsForValue
().
getAndSet
(
key
,
value
);
}
catch
(
Exception
e
){
e
.
printStackTrace
();
}
return
result
;
}
/**
* 根据key获取对象
*
...
...
@@ -190,6 +211,7 @@ public class RedisRepository {
return
redisTemplate
.
execute
(
connection
->
deserializeValue
(
connection
.
get
(
rawKey
),
valueSerializer
),
true
);
}
/**
* Ops for hash hash operations.
*
...
...
zlt-uaa/src/main/java/com/central/oauth/config/RedisListenerConfig.java
0 → 100644
浏览文件 @
0a5fdf63
package
com.central.oauth.config
;
import
org.springframework.beans.factory.annotation.Qualifier
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.context.annotation.Primary
;
import
org.springframework.data.redis.connection.RedisConnectionFactory
;
import
org.springframework.data.redis.listener.RedisMessageListenerContainer
;
/**
*
* redis过期key监听器配置类
* @author zlt
*
*/
@Configuration
public
class
RedisListenerConfig
{
@Bean
@Primary
public
RedisMessageListenerContainer
redisMessageListenerContainer
(
RedisConnectionFactory
connectionFactory
)
{
RedisMessageListenerContainer
container
=
new
RedisMessageListenerContainer
();
container
.
setConnectionFactory
(
connectionFactory
);
return
container
;
}
}
zlt-uaa/src/main/java/com/central/oauth/listener/RedisKeyExpirationListener.java
0 → 100644
浏览文件 @
0a5fdf63
package
com.central.oauth.listener
;
import
com.central.common.constant.SecurityConstants
;
import
com.central.common.redis.template.RedisRepository
;
import
lombok.extern.slf4j.Slf4j
;
import
org.apache.commons.lang3.StringUtils
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.beans.factory.annotation.Qualifier
;
import
org.springframework.data.redis.connection.Message
;
import
org.springframework.data.redis.connection.RedisConnection
;
import
org.springframework.data.redis.connection.RedisConnectionFactory
;
import
org.springframework.data.redis.listener.KeyExpirationEventMessageListener
;
import
org.springframework.data.redis.listener.RedisMessageListenerContainer
;
import
org.springframework.security.oauth2.provider.OAuth2Authentication
;
import
org.springframework.security.oauth2.provider.token.store.redis.JdkSerializationStrategy
;
import
org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStoreSerializationStrategy
;
import
org.springframework.stereotype.Component
;
/**
*
* redis过期key监听器
* @author zlt
*
*/
@Component
@Slf4j
public
class
RedisKeyExpirationListener
extends
KeyExpirationEventMessageListener
{
@Autowired
private
RedisRepository
redisRepository
;
private
RedisTokenStoreSerializationStrategy
serializationStrategy
=
new
JdkSerializationStrategy
();
private
final
RedisConnectionFactory
connectionFactory
;
public
RedisKeyExpirationListener
(
RedisMessageListenerContainer
listenerContainer
,
RedisConnectionFactory
connectionFactory
)
{
super
(
listenerContainer
);
this
.
connectionFactory
=
connectionFactory
;
}
@Override
public
void
onMessage
(
Message
message
,
byte
[]
pattern
)
{
if
(
message
==
null
)
{
log
.
debug
(
"message不能为空"
);
return
;
}
//获取失效的的key
String
expiredKey
=
message
.
toString
();
if
(
StringUtils
.
isEmpty
(
expiredKey
))
{
log
.
debug
(
"expiredKey不能为空"
);
return
;
}
String
accesskey
=
expiredKey
.
substring
(
0
,
expiredKey
.
indexOf
(
":"
)
+
1
);
if
(!
"access:"
.
equals
(
accesskey
))
{
log
.
debug
(
"非需要监听key,跳过"
);
return
;
}
String
accessValue
=
expiredKey
.
substring
(
expiredKey
.
indexOf
(
":"
)
+
1
);
// 分布式集群部署下防止一个过期被多个服务重复消费
String
qc
=
redisRepository
.
getAndSet
(
"qc:"
+
accessValue
,
"1"
);
if
(
StringUtils
.
isNotEmpty
(
qc
)
&&
"1"
.
equals
(
qc
))
{
log
.
debug
(
"其他节点已经处理了该数据,次数跳过"
);
return
;
}
byte
[]
accessBakKey
=
serializeKey
(
SecurityConstants
.
ACCESS_BAK
+
accessValue
);
byte
[]
authKey
=
serializeKey
(
SecurityConstants
.
REDIS_TOKEN_AUTH
+
accessValue
);
RedisConnection
conn
=
getConnection
();
try
{
byte
[]
access
=
conn
.
get
(
accessBakKey
);
byte
[]
auth
=
conn
.
get
(
authKey
);
OAuth2Authentication
authentication
=
deserializeAuthentication
(
auth
);
if
(
authentication
!=
null
)
{
byte
[]
unameKey
=
serializeKey
(
SecurityConstants
.
REDIS_UNAME_TO_ACCESS
+
getApprovalKey
(
authentication
));
byte
[]
clientId
=
serializeKey
(
SecurityConstants
.
REDIS_CLIENT_ID_TO_ACCESS
+
authentication
.
getOAuth2Request
().
getClientId
());
conn
.
openPipeline
();
conn
.
lRem
(
unameKey
,
1
,
access
);
conn
.
lRem
(
clientId
,
1
,
access
);
conn
.
closePipeline
();
}
}
catch
(
Exception
e
)
{
log
.
error
(
e
.
getMessage
());
}
finally
{
conn
.
del
();
conn
.
close
();
}
}
private
byte
[]
serializeKey
(
String
object
)
{
return
serialize
(
""
+
object
);
}
private
byte
[]
serialize
(
String
string
)
{
return
serializationStrategy
.
serialize
(
string
);
}
private
RedisConnection
getConnection
()
{
return
connectionFactory
.
getConnection
();
}
private
OAuth2Authentication
deserializeAuthentication
(
byte
[]
bytes
)
{
return
serializationStrategy
.
deserialize
(
bytes
,
OAuth2Authentication
.
class
);
}
private
static
String
getApprovalKey
(
OAuth2Authentication
authentication
)
{
String
userName
=
authentication
.
getUserAuthentication
()
==
null
?
""
:
authentication
.
getUserAuthentication
().
getName
();
return
getApprovalKey
(
authentication
.
getOAuth2Request
().
getClientId
(),
userName
);
}
private
static
String
getApprovalKey
(
String
clientId
,
String
userName
)
{
return
clientId
+
(
userName
==
null
?
""
:
":"
+
userName
);
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录