技术背景
在分布式系统中,令牌(Token)被广泛应用于身份认证成功后对系统的访问控制。在本文中,我们实现了一个简单的令牌颁发与管理服务,其中包含访问令牌(AccessToken)和刷新令牌(RefreshToken)两种类型的令牌。
功能需求
- 颁发刷新令牌和访问令牌
- 验证和管理访问令牌
- 支持刷新令牌的续期
技术实现
配置
- 该代码实现时是用了redis,此时环境中使用的是debina12.5和redis server v=7.0.15
- maven工程pom导入
<dependencies> <!-- redis客户端 --> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>3.7.1</version> </dependency> <!-- json tool --> <dependency> <groupId>com.alibaba.fastjson2</groupId> <artifactId>fastjson2</artifactId> <version>2.0.26</version> </dependency> </dependencies>
代码实现
package com.qcmb.token.service;
/**
* 令牌模型
*/
public class Token {
//令牌唯一标识
protected String id;
public String getId() {
return id;
}
//令牌颁发时间 (毫秒)
protected long issueTime;
public long getIssueTime() {
return issueTime;
}
//令牌的过期时间 (秒)
protected int expirationSecond;
public int getExpirationSecond() {
return expirationSecond;
}
//与用户关联的id
protected String userId;
public String getUserId() {
return userId;
}
}
package com.qcmb.token.service;
/**
* 短生命周期的令牌用于
* 可用于验证用户访问资源
*/
public class AccessToken extends Token{
public void setId(String id) {
this.id = id;
}
public void setUserId(String userId){
this.userId = userId;
}
public void setIssueTime(long issueTime){
this.issueTime = issueTime;
}
public void setExpirationSecond(int expirationSecond){
this.expirationSecond = expirationSecond;
}
public AccessToken(){
super();
}
//默认生命为30分钟
public AccessToken(String userId,String accessTokenId){
//在使用fsatjson反序列话的时候会调用构造方法,为了防止它调用此构造方法。我们必须写出一个无参的构造方法,它会调用这个无参的构造。
//令牌颁发时间
this.issueTime = System.currentTimeMillis();
//令牌过期时间,默认30分钟
this.expirationSecond = 30*60;
//this.expirationSecond = 10;
this.userId = userId;
this.id = accessTokenId;
}
}
package com.qcmb.token.service;
/**
* 长生命周期令牌
* 只能用来生成短声明 AccessToken
*/
public class RefreshToken extends Token{
private String accessTokenId;
public void setId(String id) {
this.id = id;
}
public void setUserId(String userId){
this.userId = userId;
}
public void setIssueTime(long issueTime){
this.issueTime = issueTime;
}
public void setExpirationSecond(int expirationSecond){
this.expirationSecond = expirationSecond;
}
public void setAccessTokenId(String accessTokenId) {
this.accessTokenId = accessTokenId;
}
public String getAccessTokenId() {
return accessTokenId;
}
public RefreshToken(){
super();
}
//过期时间默认7天
public RefreshToken(String userId,String tokenId){
//在使用fsatjson反序列话的时候会调用构造方法,为了防止它调用此构造方法。我们必须写出一个无参的构造方法,它会调用这个无参的构造。
//令牌颁发时间
this.issueTime = System.currentTimeMillis();
//令牌过期时间,默认7天
this.expirationSecond = 7 * 24 * 60 * 60;
//this.expirationSecond = 50;
this.userId = userId;
this.id = tokenId;
}
}
package com.qcmb.token.service;
/**
* redis配置
*/
public class MyRedisConfigBean {
public String getRedis_host() {
return redis_host;
}
public void setRedis_host(String redis_host) {
this.redis_host = redis_host;
}
public Integer getRedis_port() {
return redis_port;
}
public void setRedis_port(Integer redis_port) {
this.redis_port = redis_port;
}
public String getRedis_password() {
return redis_password;
}
public void setRedis_password(String redis_password) {
this.redis_password = redis_password;
}
public Integer getRedis_timeout() {
return redis_timeout;
}
public void setRedis_timeout(Integer redis_timeout) {
this.redis_timeout = redis_timeout;
}
public Integer getRedis_pool_maxTotal() {
return redis_pool_maxTotal;
}
public void setRedis_pool_maxTotal(Integer redis_pool_maxTotal) {
this.redis_pool_maxTotal = redis_pool_maxTotal;
}
public Integer getRedis_pool_maxIdle() {
return redis_pool_maxIdle;
}
public void setRedis_pool_maxIdle(Integer redis_pool_maxIdle) {
this.redis_pool_maxIdle = redis_pool_maxIdle;
}
public Integer getRedis_pool_minIdle() {
return redis_pool_minIdle;
}
public void setRedis_pool_minIdle(Integer redis_pool_minIdle) {
this.redis_pool_minIdle = redis_pool_minIdle;
}
public Integer getRedis_pool_maxWaitMillis() {
return redis_pool_maxWaitMillis;
}
public void setR