Redis jti repository impl/ test
parent
a5592cf054
commit
688c47a6f6
4
pom.xml
4
pom.xml
|
@ -65,6 +65,10 @@
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-data-redis</artifactId>
|
<artifactId>spring-boot-starter-data-redis</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.commons</groupId>
|
||||||
|
<artifactId>commons-pool2</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|
|
@ -39,7 +39,8 @@ public class ClaimsOAuth2TokenCustomizer implements OAuth2TokenCustomizer<JwtEnc
|
||||||
|
|
||||||
JwtClaimsSet.Builder claims = context.getClaims();
|
JwtClaimsSet.Builder claims = context.getClaims();
|
||||||
//jti
|
//jti
|
||||||
claims.id(GuidGenerator.generateNumber());
|
String jti = GuidGenerator.generateNumber();
|
||||||
|
claims.id(jti);
|
||||||
|
|
||||||
//根据不同的 scope 与 tokenType添加扩展属性
|
//根据不同的 scope 与 tokenType添加扩展属性
|
||||||
OAuth2TokenType tokenType = context.getTokenType();
|
OAuth2TokenType tokenType = context.getTokenType();
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
package com.monkeyk.sos.domain.oauth;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 2025/5/28 17:19
|
||||||
|
*
|
||||||
|
* @author Shengzhao Li
|
||||||
|
* @since 3.0.1
|
||||||
|
*/
|
||||||
|
public interface JtiRepository {
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存 JtiToken
|
||||||
|
*
|
||||||
|
* @param jtiToken JtiToken
|
||||||
|
* @param ttl 有效时间,秒
|
||||||
|
*/
|
||||||
|
void saveJtiToken(JtiToken jtiToken, long ttl);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询
|
||||||
|
*
|
||||||
|
* @param jti jti
|
||||||
|
* @return JtiToken
|
||||||
|
*/
|
||||||
|
JtiToken findByJti(String jti);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断对应的 jti 是否存在(一般存在表示还可用?),根据 jti
|
||||||
|
*
|
||||||
|
* @param jti jti
|
||||||
|
* @return true 存在
|
||||||
|
*/
|
||||||
|
boolean existJti(String jti);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除 Jti 数据
|
||||||
|
*
|
||||||
|
* @param jti jti
|
||||||
|
* @return 删除成功返回 true
|
||||||
|
*/
|
||||||
|
Boolean removeJtiToken(String jti);
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,73 @@
|
||||||
|
package com.monkeyk.sos.domain.oauth;
|
||||||
|
|
||||||
|
import java.io.Serial;
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 2025/5/28 17:16
|
||||||
|
*
|
||||||
|
* @author Shengzhao Li
|
||||||
|
* @since 3.0.0
|
||||||
|
*/
|
||||||
|
public class JtiToken implements Serializable {
|
||||||
|
@Serial
|
||||||
|
private static final long serialVersionUID = -6826558386135443094L;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* jti值,从id_token 获取
|
||||||
|
*/
|
||||||
|
private String jti;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* OAuth2 clientId
|
||||||
|
*/
|
||||||
|
private String clientId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* user id,可选
|
||||||
|
*/
|
||||||
|
private String userId;
|
||||||
|
|
||||||
|
// 可扩展其他属性
|
||||||
|
|
||||||
|
|
||||||
|
public JtiToken() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getJti() {
|
||||||
|
return jti;
|
||||||
|
}
|
||||||
|
|
||||||
|
public JtiToken setJti(String jti) {
|
||||||
|
this.jti = jti;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getClientId() {
|
||||||
|
return clientId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public JtiToken setClientId(String clientId) {
|
||||||
|
this.clientId = clientId;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUserId() {
|
||||||
|
return userId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public JtiToken setUserId(String userId) {
|
||||||
|
this.userId = userId;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "{" +
|
||||||
|
"jti='" + jti + '\'' +
|
||||||
|
", clientId='" + clientId + '\'' +
|
||||||
|
", userId='" + userId + '\'' +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,96 @@
|
||||||
|
package com.monkeyk.sos.infrastructure.redis;
|
||||||
|
|
||||||
|
import com.monkeyk.sos.domain.oauth.JtiRepository;
|
||||||
|
import com.monkeyk.sos.domain.oauth.JtiToken;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.data.redis.core.BoundValueOperations;
|
||||||
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 2025/5/28 17:22
|
||||||
|
*
|
||||||
|
* @author Shengzhao Li
|
||||||
|
* @since 3.0.1
|
||||||
|
*/
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public class JtiRepositoryRedis implements JtiRepository {
|
||||||
|
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(JtiRepositoryRedis.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* KEY的格式
|
||||||
|
*/
|
||||||
|
private static final String KEY_FORMAT = "sos-jti-%s";
|
||||||
|
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private RedisTemplate<Object, Object> redisTemplate;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 统一加前缀
|
||||||
|
*
|
||||||
|
* @param jti jti
|
||||||
|
* @return redis key
|
||||||
|
*/
|
||||||
|
private String getJtiRedisKey(String jti) {
|
||||||
|
return String.format(KEY_FORMAT, jti);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void saveJtiToken(JtiToken jtiToken, long ttl) {
|
||||||
|
if (ttl <= 0) {
|
||||||
|
throw new IllegalArgumentException("ttl must be greater than 0");
|
||||||
|
}
|
||||||
|
String redisKey = getJtiRedisKey(jtiToken.getJti());
|
||||||
|
if (LOG.isTraceEnabled()) {
|
||||||
|
LOG.trace("saveJtiToken, jtiToken: {}, ttl: {}", jtiToken, ttl);
|
||||||
|
}
|
||||||
|
BoundValueOperations<Object, Object> bvo = this.redisTemplate.boundValueOps(redisKey);
|
||||||
|
bvo.set(jtiToken, ttl, TimeUnit.SECONDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public JtiToken findByJti(String jti) {
|
||||||
|
String redisKey = getJtiRedisKey(jti);
|
||||||
|
BoundValueOperations<Object, Object> bvo = this.redisTemplate.boundValueOps(redisKey);
|
||||||
|
return (JtiToken) bvo.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean existJti(String jti) {
|
||||||
|
String redisKey = getJtiRedisKey(jti);
|
||||||
|
Boolean has = this.redisTemplate.hasKey(redisKey);
|
||||||
|
return has != null ? has : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Boolean removeJtiToken(String jti) {
|
||||||
|
String redisKey = getJtiRedisKey(jti);
|
||||||
|
return this.redisTemplate.delete(redisKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -24,11 +24,12 @@ spring.security.oauth2.authorizationserver.issuer=http://127.0.0.1:${server.port
|
||||||
#
|
#
|
||||||
# Redis
|
# Redis
|
||||||
#
|
#
|
||||||
spring.data.redis.host=localhost
|
spring.data.redis.host=127.0.0.1
|
||||||
spring.data.redis.port=6379
|
spring.data.redis.port=6379
|
||||||
spring.data.redis.database=5
|
spring.data.redis.database=5
|
||||||
spring.data.redis.password=
|
spring.data.redis.password=
|
||||||
spring.data.redis.timeout=2000
|
spring.data.redis.timeout=2000
|
||||||
|
spring.data.redis.lettuce.pool.enabled=true
|
||||||
#
|
#
|
||||||
# Condition Config
|
# Condition Config
|
||||||
# @since 2.1.0
|
# @since 2.1.0
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
package com.monkeyk.sos.infrastructure.redis;
|
||||||
|
|
||||||
|
import com.monkeyk.sos.domain.oauth.JtiToken;
|
||||||
|
import com.monkeyk.sos.infrastructure.AbstractRepositoryTest;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 2025/5/28 17:33
|
||||||
|
*
|
||||||
|
* @author Shengzhao Li
|
||||||
|
* @since 3.0.1
|
||||||
|
*/
|
||||||
|
//@Transactional
|
||||||
|
class JtiRepositoryRedisTest extends AbstractRepositoryTest {
|
||||||
|
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private JtiRepositoryRedis repositoryRedis;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void saveJtiToken() {
|
||||||
|
|
||||||
|
JtiToken jtiToken = new JtiToken()
|
||||||
|
.setJti("jti").setClientId("clientId").setUserId("userId");
|
||||||
|
|
||||||
|
repositoryRedis.saveJtiToken(jtiToken, 1000);
|
||||||
|
|
||||||
|
repositoryRedis.removeJtiToken(jtiToken.getJti());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void findByJti() {
|
||||||
|
|
||||||
|
JtiToken jtiToken = repositoryRedis.findByJti("jti");
|
||||||
|
assertNull(jtiToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void existJti() {
|
||||||
|
|
||||||
|
boolean exist = repositoryRedis.existJti("jti");
|
||||||
|
assertFalse(exist);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue