package com.oying.modules.security.security;
|
|
import cn.hutool.core.date.DateField;
|
import cn.hutool.core.date.DateUtil;
|
import cn.hutool.core.util.IdUtil;
|
import com.oying.modules.security.service.dto.JwtUserDto;
|
import io.jsonwebtoken.*;
|
import io.jsonwebtoken.io.Decoders;
|
import io.jsonwebtoken.security.Keys;
|
import lombok.RequiredArgsConstructor;
|
import lombok.extern.slf4j.Slf4j;
|
import com.oying.modules.security.config.SecurityProperties;
|
import com.oying.utils.RedisUtils;
|
import org.springframework.beans.factory.InitializingBean;
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.userdetails.User;
|
import org.springframework.stereotype.Component;
|
import javax.servlet.http.HttpServletRequest;
|
import java.security.Key;
|
import java.util.*;
|
import java.util.concurrent.TimeUnit;
|
|
/**
|
* @author Z
|
*/
|
@Slf4j
|
@Component
|
@RequiredArgsConstructor
|
public class TokenProvider implements InitializingBean {
|
|
private JwtParser jwtParser;
|
private JwtBuilder jwtBuilder;
|
private final RedisUtils redisUtils;
|
private final SecurityProperties properties;
|
public static final String AUTHORITIES_UUID_KEY = "uid";
|
public static final String AUTHORITIES_UID_KEY = "userId";
|
|
@Override
|
public void afterPropertiesSet() {
|
byte[] keyBytes = Decoders.BASE64.decode(properties.getBase64Secret());
|
Key key = Keys.hmacShaKeyFor(keyBytes);
|
jwtParser = Jwts.parserBuilder()
|
.setSigningKey(key)
|
.build();
|
jwtBuilder = Jwts.builder()
|
.signWith(key, SignatureAlgorithm.HS512);
|
}
|
|
/**
|
* 创建Token 设置永不过期,
|
* Token 的时间有效性转到Redis 维护
|
* @param user /
|
* @return /
|
*/
|
public String createToken(JwtUserDto user) {
|
// 设置参数
|
Map<String, Object> claims = new HashMap<>(6);
|
// 设置用户ID
|
claims.put(AUTHORITIES_UID_KEY, user.getUser().getId());
|
// 设置UUID,确保每次Token不一样
|
claims.put(AUTHORITIES_UUID_KEY, IdUtil.simpleUUID());
|
return jwtBuilder
|
.setClaims(claims)
|
.setSubject(user.getUsername())
|
.compact();
|
}
|
|
/**
|
* 依据Token 获取鉴权信息
|
*
|
* @param token /
|
* @return /
|
*/
|
Authentication getAuthentication(String token) {
|
Claims claims = getClaims(token);
|
User principal = new User(claims.getSubject(), "******", new ArrayList<>());
|
return new UsernamePasswordAuthenticationToken(principal, token, new ArrayList<>());
|
}
|
|
public Claims getClaims(String token) {
|
return jwtParser
|
.parseClaimsJws(token)
|
.getBody();
|
}
|
|
/**
|
* @param token 需要检查的token
|
*/
|
public void checkRenewal(String token) {
|
// 判断是否续期token,计算token的过期时间
|
String loginKey = loginKey(token);
|
long time = redisUtils.getExpire(loginKey) * 1000;
|
Date expireDate = DateUtil.offset(new Date(), DateField.MILLISECOND, (int) time);
|
// 判断当前时间与过期时间的时间差
|
long differ = expireDate.getTime() - System.currentTimeMillis();
|
// 如果在续期检查的范围内,则续期
|
if (differ <= properties.getDetect()) {
|
long renew = time + properties.getRenew();
|
redisUtils.expire(loginKey, renew, TimeUnit.MILLISECONDS);
|
}
|
}
|
|
public String getToken(HttpServletRequest request) {
|
final String requestHeader = request.getHeader(properties.getHeader());
|
if (requestHeader != null && requestHeader.startsWith(properties.getTokenStartWith())) {
|
return requestHeader.substring(7);
|
}
|
return null;
|
}
|
|
/**
|
* 获取登录用户RedisKey
|
* @param token /
|
* @return key
|
*/
|
public String loginKey(String token) {
|
Claims claims = getClaims(token);
|
return properties.getOnlineKey() + claims.getSubject() + ":" + getId(token);
|
}
|
|
/**
|
* 获取会话编号
|
* @param token /
|
* @return /
|
*/
|
public String getId(String token) {
|
Claims claims = getClaims(token);
|
return claims.get(AUTHORITIES_UUID_KEY, String.class);
|
}
|
}
|