一、生成Token前的校验工作
//生成了密钥,CAPTCHA_CODE_KEY = "captcha_codes:",uuid是唯一标识
//在我们登录的时候就已经将UUID+标识符放入了redis缓存中
String verifyKey = Constants.CAPTCHA_CODE_KEY + uuid;
//去redis中获取了这个值
String captcha = redisCache.getCacheObject(verifyKey);
//删除了密钥,这是验证产生是产生的
redisCache.deleteObject(verifyKey);
//如果没有拿到密钥下的值,说明缓存中的数据过期了
//下面就根据是否有值来走不同的业务
if (captcha == null)
{
}
//验证码跟我们传过去的不一样,用户的验证码输入错误了
if (!code.equalsIgnoreCase(captcha))
{
}
//检查密码
// 用户验证
//下面就可以生成Token了
二、开始生成Token的内容数据
/**
* 创建令牌
* @param loginUser 用户信息
* @return 令牌
*/
public String createToken(LoginUser loginUser) {
//重新生成uuid
String token = IdUtils.fastUUID();
//将UUID设置为我们的唯一标识
loginUser.setToken(token);
//设置用户代理
setUserAgent(loginUser);
//刷新令牌
refreshToken(loginUser);
//令牌指令加生的uuid
Map claims = new HashMap<>();
//这里放了令牌前缀
claims.put(Constants.LOGIN_USER_KEY, token);
//存放非敏感信息
claims.put("username",loginUser.getUsername());
claims.put("nickName",loginUser.getUser().getNickName());
claims.put("createTime",loginUser.getUser().getCreateTime());
return createToken(claims);
}
在创建令牌前我们刷新了UserLogin类的过期时间,放到了Redis
/**
* 刷新令牌有效期
* @param loginUser 登录信息
*/
public void refreshToken(LoginUser loginUser)
{
//获取令牌,设置令牌的时间为当前的系统时间
loginUser.setLoginTime(System.currentTimeMillis());
//再为令牌增加默认的30分钟
loginUser.setExpireTime(loginUser.getLoginTime() + expireTime * MILLIS_MINUTE);
// 根据uuid将loginUser缓存,拿到用户修改之后的token
String userKey = getTokenKey(loginUser.getToken());
//重新将缓存中的用户数据刷新
redisCache.setCacheObject(userKey, loginUser, expireTime, TimeUnit.MINUTES);
}
三、开始创建Token
/**
* 从数据声明生成令牌
* @param claims 数据声明
* @return 令牌
*/
private String createToken(Map claims)
{
//返回令牌
String token = Jwts.builder()
.setClaims(claims)
//在这里生成我们的tokne,同时用我们的签名进行了加密
//这里面放了姓名,创建时间
.signWith(SignatureAlgorithm.HS512, secret).compact();
return token
整体代码如下
/**
* token验证处理
*
*
*/
@Component
public class TokenService {
// 令牌自定义标识
@Value("${token.header}")
private String header;
// 令牌秘钥
@Value("${token.secret}")
private String secret;
// 令牌有效期(默认30分钟)
@Value("${token.expireTime}")
private int expireTime;
protected static final long MILLIS_SECOND = 1000;
protected static final long MILLIS_MINUTE = 60 * MILLIS_SECOND;
private static final Long MILLIS_MINUTE_TEN = 20 * 60 * 1000L;
@Autowired
private RedisCache redisCache;
/**
* 获取用户身份信息
*
* @return 用户信息
*/
public LoginUser getLoginUser(HttpServletRequest request) {
// 获取请求携带的令牌
String token = getToken(request);
if (StringUtils.isNotEmpty(token)) {
Claims claims = parseToken(token);
// 解析对应的权限以及用户信息
String uuid = (String) claims.get(Constants.LOGIN_USER_KEY);
String userKey = getTokenKey(uuid);
LoginUser user = redisCache.getCacheObject(userKey);
return user;
}
return null;
}
/**
* 设置用户身份信息
*/
public void setLoginUser(LoginUser loginUser)
{
if (StringUtils.isNotNull(loginUser) && StringUtils.isNotEmpty(loginUser.getToken()))
{
refreshToken(loginUser);
}
}
/**
* 删除用户身份信息
*/
public void delLoginUser(String token)
{
if (StringUtils.isNotEmpty(token))
{
String userKey = getTokenKey(token);
redisCache.deleteObject(userKey);
}
}
/**
* 创建令牌
* @param loginUser 用户信息
* @return 令牌
*/
public String createToken(LoginUser loginUser) {
//重新生成uuid
String token = IdUtils.fastUUID();
//将UUID设置为我们的唯一标识
loginUser.setToken(token);
//设置用户代理
setUserAgent(loginUser);
//刷新令牌
refreshToken(loginUser);
//令牌指令加生的uuid
Map claims = new HashMap<>();
// LOGIN_USER_KEY = "login_user_key"; 令牌前缀,就是UUID
claims.put(Constants.LOGIN_USER_KEY, token);
//存放非敏感信息
claims.put("username",loginUser.getUsername());
claims.put("nickName",loginUser.getUser().getNickName());
claims.put("createTime",loginUser.getUser().getCreateTime());
return createToken(claims);
}
/**
* 验证令牌有效期,相差不足20分钟,自动刷新缓存
* @param loginUser
* @return 令牌
*/
public void verifyToken(LoginUser loginUser)
{
//获取令牌中的过期时间
long expireTime = loginUser.getExpireTime();
//获取当前的系统时间
long currentTime = System.currentTimeMillis();
//如果二者的时间差小于20分钟
if (expireTime - currentTime <= MILLIS_MINUTE_TEN)
{
refreshToken(loginUser);
}
}
/**
* 刷新令牌有效期
* @param loginUser 登录信息
*/
public void refreshToken(LoginUser loginUser)
{
//获取令牌,设置令牌的时间为当前的系统时间
loginUser.setLoginTime(System.currentTimeMillis());
//再为令牌增加默认的30分钟
loginUser.setExpireTime(loginUser.getLoginTime() + expireTime * MILLIS_MINUTE);
// 根据uuid将loginUser缓存,拿到用户修改之后的token
String userKey = getTokenKey(loginUser.getToken());
//重新将缓存中的用户数据刷新
redisCache.setCacheObject(userKey, loginUser, expireTime, TimeUnit.MINUTES);
}
/**
* 设置用户代理信
* @param loginUser 登录信息
*/
public void setUserAgent(LoginUser loginUser)
{
UserAgent userAgent = UserAgent.parseUserAgentString(ServletUtils.getRequest().getHeader("User-Agent"));
String ip = IpUtils.getIpAddr(ServletUtils.getRequest());
loginUser.setIpaddr(ip);
loginUser.setLoginLocation(AddressUtils.getRealAddressByIP(ip));
loginUser.setBrowser(userAgent.getBrowser().getName());
loginUser.setOs(userAgent.getOperatingSystem().getName());
}
/**
* 从数据声明生成令牌
* @param claims 数据声明
* @return 令牌
*/
private String createToken(Map claims)
{
//返回令牌
String token = Jwts.builder()
.setClaims(claims)
//在这里生成我们的tokne,同时用我们的签名进行了加密
//这里面放了姓名,创建时间
.signWith(SignatureAlgorithm.HS512, secret).compact();
return token;
}
/**
* 从令牌中获取数据声明
*
* @param token 令牌
* @return 数据声明
*/
private Claims parseToken(String token)
{
return Jwts.parser()
.setSigningKey(secret)
.parseClaimsJws(token)
.getBody();
}
/**
* 从令牌中获取用户名
*
* @param token 令牌
* @return 用户名
*/
public String getUsernameFromToken(String token)
{
Claims claims = parseToken(token);
return claims.getSubject();
}
/**
* 获取请求token
*
* @param request
* @return token
*/
private String getToken(HttpServletRequest request)
{
String token = request.getHeader(header);
if (StringUtils.isNotEmpty(token) && token.startsWith(Constants.TOKEN_PREFIX))
{
token = token.replace(Constants.TOKEN_PREFIX, "");
}
return token;
}
private String getTokenKey(String uuid)
{
return Constants.LOGIN_TOKEN_KEY + uuid;
}
}