一、gradle引入依赖
// jjwt
implementation 'io.jsonwebtoken:jjwt-api:0.11.1'
runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.11.1'
runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.11.1'
二、JwtTokenUtil.java工具
1、配置文件中添加
## JWT 密钥 - start
jwt:
secret-key: 789qweq44878877qsdgrtqw848fg789qweq44878877qsfg)
access-token-expire-time: PT2H
refresh-token-expire-time: PT8H
refresh-token-expire-app-time: P30D
issuer: zz.com
## JWT 密钥 - end
创建映射类
@Configuration
@ConfigurationProperties(prefix = "jwt")
public class TokenSettings {
private String secretKey;
private Duration accessTokenExpireTime;
private Duration refreshTokenExpireTime;
private Duration refreshTokenExpireAppTime;
private String issuer;
get/set。。。
}
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
import java.security.Key;
import java.time.Duration;
import java.util.Date;
import java.util.Map;
/**
* @ClassName : JwtTokenUtil.java
* @Description : 描述
* @Author : zhangz
* @createTime 2020年07月27日 11:31:00
*/
public class JwtTokenUtil {
private static final Logger log = LoggerFactory.getLogger(JwtTokenUtil.class);
private static String secretKey;
private static Duration accessTokenExpireTime;
private static Duration refreshTokenExpireTime;
private static Duration refreshTokenExpireAppTime;
private static String issuer;
public static void setTokenSettings(TokenSettings tokenSettings){
secretKey=tokenSettings.getSecretKey();
accessTokenExpireTime=tokenSettings.getAccessTokenExpireTime();
refreshTokenExpireTime=tokenSettings.getRefreshTokenExpireTime();
refreshTokenExpireAppTime=tokenSettings.getRefreshTokenExpireAppTime();
issuer=tokenSettings.getIssuer();
}
/**
* 生成 access_token
* @return java.lang.String
*/
public static String getAccessToken(String subject, Map<String,Object> claims){
return generateToken(issuer,subject,claims,accessTokenExpireTime.toMillis(),secretKey);
}
/**
* 生产 App端 refresh_token
* @return java.lang.String
*/
public static String getRefreshAppToken(String subject,Map<String,Object> claims){
return generateToken(issuer,subject,claims,refreshTokenExpireAppTime.toMillis(),secretKey);
}
/**
* 生产 PC refresh_token
* @return java.lang.String
*/
public static String getRefreshToken(String subject,Map<String,Object> claims){
return generateToken(issuer,subject,claims,refreshTokenExpireTime.toMillis(),secretKey);
}
/**
* 签发token
* @param issuer 签发人
* @param subject 代表这个JWT的主体,即它的所有人 一般是用户id
* @param claims 存储在JWT里面的信息 一般放些用户的权限/角色信息
* @param ttlMillis 有效时间(毫秒)
* @return java.lang.String
*/
public static String generateToken(String issuer, String subject,Map<String, Object> claims, long ttlMillis,String secret) {
// Key key = Keys.secretKeyFor(SignatureAlgorithm.HS256);
SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
long nowMillis = System.currentTimeMillis();
Date now = new Date(nowMillis);
byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary(secret);
Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName());
JwtBuilder builder = Jwts.builder();
if(null!=claims){
builder.setClaims(claims);
}
if (!StringUtils.isEmpty(subject)) {
builder.setSubject(subject);
}
if (!StringUtils.isEmpty(issuer)) {
builder.setIssuer(issuer);
}
builder.setIssuedAt(now);
if (ttlMillis >= 0) {
long expMillis = nowMillis + ttlMillis;
Date exp = new Date(expMillis);
builder.setExpiration(exp);
}
builder.signWith(signingKey);
return builder.compact();
}
/**
* 获取用户id
* @return java.lang.String
*/
public static String getUserId(String token){
String userId=null;
try {
Claims claims = getClaimsFromToken(token);
userId = claims.getSubject();
} catch (Exception e) {
log.error("eror={}",e);
}
return userId;
}
/**
* 获取用户名
* @return java.lang.String
*/
public static String getUserName(String token){
String username=null;
try {
Claims claims = getClaimsFromToken(token);
username = (String) claims .get(Constant.JWT_USER_NAME);
} catch (Exception e) {
log.error("eror={}",e);
}
return username;
}
/**
* 获取用户电话
* @return java.lang.String
*/
public static String getUserMobile(String token){
String userMobile=null;
try {
Claims claims = getClaimsFromToken(token);
userMobile = (String) claims .get(Constant.JWT_USER_MOBILE);
} catch (Exception e) {
log.error("eror={}",e);
}
return userMobile;
}
/**
* 从令牌中获取数据声明
* @return io.jsonwebtoken.Claims
*/
public static Claims getClaimsFromToken(String token) {
Claims claims;
try {
claims = Jwts.parser().setSigningKey(DatatypeConverter.parseBase64Binary(secretKey)).parseClaimsJws(token).getBody();
} catch (Exception e) {
claims = null;
}
return claims;
}
/**
* 校验令牌
* @return java.lang.Boolean
*/
public static Boolean validateToken(String token) {
Claims claimsFromToken = getClaimsFromToken(token);
return (null!=claimsFromToken && !isTokenExpired(token));
}
/**
* 验证token 是否过期
* @return java.lang.Boolean
*/
public static Boolean isTokenExpired(String token) {
try {
Claims claims = getClaimsFromToken(token);
Date expiration = claims.getExpiration();
return expiration.before(new Date());
} catch (Exception e) {
log.error("error={}",e);
return true;
}
}
/**
* 刷新token
* @return java.lang.String
*/
public static String refreshToken(String refreshToken,Map<String, Object> claims) {
String refreshedToken;
try {
Claims parserclaims = getClaimsFromToken(refreshToken);
/**
* 刷新token的时候如果为空说明原先的 用户信息不变 所以就引用上个token里的内容
*/
if(null==claims){
claims=parserclaims;
}
refreshedToken = generateToken(parserclaims.getIssuer(),parserclaims.getSubject(),claims,accessTokenExpireTime.toMillis(),secretKey);
} catch (Exception e) {
refreshedToken = null;
log.error("error={}",e);
}
return refreshedToken;
}
/**
* 获取token的剩余过期时间
* @return long
*/
public static long getRemainingTime(String token){
long result=0;
try {
long nowMillis = System.currentTimeMillis();
result= getClaimsFromToken(token).getExpiration().getTime()-nowMillis;
} catch (Exception e) {
log.error("error={}",e);
}
return result;
}
三、登录时生成token
@Override
public Map<String, Object> login(User vo) {
User user = userRepository.findByUserMobile(vo.getUserMobile()); // 数据库查询
if (BeanUtil.isNotEmpty(user)) {
if(!PasswordUtils.matches(user.getSalt(),vo.getUserPassword(),user.getUserPassword())){
throw new BusinessException(BaseResponseCode.PASSWORD_ERROR); // 判断密码是否正确
}
Map<String,Object> claims=new HashMap<>();
claims.put(Constant.JWT_USER_NAME,user.getUserRealName());
claims.put(Constant.JWT_USER_MOBILE,user.getUserMobile());
Map<String ,Object> map = new HashMap();
String refresh_token=JwtTokenUtil.getRefreshToken(user.getUserId().toString(),claims);
map.put("token", refresh_token);
map.put("user",user);
return map;
}
return null;
}
四、携带token进行访问验证(登录成功将token返回到前端,前端将token添加到请求头"token"中),后台携带获取token,并获取userId,获取失败则token无效
Result result = new Result();
String token = request.getHeader("token");
if(BeanUtil.isEmpty(token)){
token = request.getParameter("token");
}
// String url = request.getRequestURL().toString();
if (StringUtils.isNotBlank(token)) {
// Claims claims = JwtTokenUtil.getClaimsFromToken(token); // 从令牌中获取数据声明
// Long time = JwtTokenUtil.getRemainingTime(token); // 剩余过期时间
// Boolean b = JwtTokenUtil.validateToken(token); // 校验token
String id = JwtTokenUtil.getUserId(token); // 获取用户id
String userMobile = JwtTokenUtil.getUserMobile(token); // 获取用户电话
if (BeanUtil.isNotEmpty(id) && BeanUtil.isNotEmpty(userMobile)) {
User user = userService.getOne(Integer.parseInt(id));
if (BeanUtil.isNotEmpty(user) && user.getUserMobile().equals(userMobile)) {
if (user.getUserOn().equals(EnumUtils.UserEnum.NORMAL.getValue())) {
request.setAttribute(CommonUtil.SYSTEM_USER, user);
// 刷新token有效期
userTokenService.refresh(token);
} else {
result.setStatus(ResultCode.PARAM_ERROR);
result.setMsg("用户账号未启用,登录失败");
}
} else {
result.setStatus(ResultCode.PARAM_ERROR);
result.setMsg("账号异常,请重新尝试");
}
} else {
result.setStatus(ResultCode.PARAM_ERROR);
result.setMsg("token失效,请重新登录");
}
}