技术背景
在分布式系统中,令牌(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;}//与用户关联的idprotected 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