io.github.wslxm.springbootplus2.utils.JwtUtil Maven / Gradle / Ivy
The newest version!
package io.github.wslxm.springbootplus2.utils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import io.github.wslxm.springbootplus2.utils.model.JwtUser;
import io.github.wslxm.springbootplus2.core.config.error.ErrorException;
import io.github.wslxm.springbootplus2.core.result.Result;
import io.github.wslxm.springbootplus2.core.result.ResultType;
import io.github.wslxm.springbootplus2.manage.sys.model.vo.SysConfigVO;
import io.github.wslxm.springbootplus2.constant.ConfigCacheKey;
import io.jsonwebtoken.*;
import lombok.extern.slf4j.Slf4j;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;
/***
* jwt 工具类
*
* 使用Deflater 压缩数据后再放到 jwt存储数据,以保证不出现 header 大小问题(不能超过8kb) max-http-header-size
* jwt工具包会把最后的数据进行base64编码返回
*
* @author 王松
* @mail [email protected]
* @date 2020/7/5 0005 19:13
*/
@SuppressWarnings("all")
@Slf4j
public class JwtUtil {
private static final String SUBJECT = "xijia"; // 主题
private static final String APPSECRET_KEY = "xijia-!@#$"; // 加密key(黑客没有该值无法篡改token内容)
private static final String AUTH_USER = "user"; // 用户信息key
// TOKEN KEY值
public static String TOKEN = "token";
// TOKEN 有效期 key值, 刷新 token时动态刷新
public static String EXPIRED_TIME = "EXPIRED_TIME";
// 登录类型 0=管理端 | 1=用户端 | 2-扩展端1 | 3-扩展端2 | 4-扩展端3 | 更多自定义
public static final Integer[] userType = {0, 1, 2, 3, 4};
/**
* 生成管理端的 token
*
* @param jwtUser 用户信息
* @param refreshTime 刷新时间(分),相当于 token的有效期
* @param response
* @return java.lang.String
* @date 2020/7/6 0006 9:26
*/
public static String createToken(JwtUser jwtUser, HttpServletResponse response) {
// 压缩数据
// String deflaterJwtUser = DeflaterUtils.zipString(JsonUtil.toJSONStringNoNull(jwtUser));
String deflaterJwtUser = JSON.toJSONString(jwtUser, SerializerFeature.PrettyFormat);
// token每次刷新时长
long refreshTime = (long) (1000L * 60 * (Double.parseDouble(jwtUser.getExpiration() + "") / 10));
// 生成jwt
String jwtToken = Jwts
.builder()
// 主题
.setSubject(SUBJECT)
// 添加jwt自定义参数
.claim(AUTH_USER, deflaterJwtUser)
// 创建token 时间
.setIssuedAt(new Date())
// tokne 真实有效期,在真实有效期内, 如果 jwt-token过期了, 将自动延长有效期设置的总有效期时长, 如果在tokne 真实有效期内未使用过,则token过期
.claim(EXPIRED_TIME, System.currentTimeMillis() + (1000L * 60 * (jwtUser.getExpiration())))
// jwt-token 过期时间, jwt-token 如果过期了, 更新jwt-token参数,jwt-token参数有效期为(真实有效期/10)
.setExpiration(new Date(System.currentTimeMillis() + refreshTime))
// 加密方式,加密key
.signWith(SignatureAlgorithm.HS256, APPSECRET_KEY).compact();
// 放入 Header
response.setHeader(TOKEN, jwtToken);
return jwtToken;
}
/**
* 获取用户信息(自动区分登录类型--生成jwt时指定, jwtUser的type )
*
* 此方法用于在项目中的任意地方获取用户信息,如果在登录授权验证中未过期,但在项目使用时过期, 会在这里抛出自定义异常,程序中无需判断
*
*
* @param token
* @return
*/
public static JwtUser getJwtUser(HttpServletRequest request) {
Result jwtUser2 = getJwtUserR(request, null);
if (!jwtUser2.getCode().equals(ResultType.SYS_SUCCESS.getValue())) {
throw new ErrorException(jwtUser2.getCode(), jwtUser2.getMsg());
}
return jwtUser2.getData();
}
/**
* 获取登录信息,如过 token无效过期等,会进入对应的异常信息中返回
*
* 1、此方法用于权限验证, aop中,日志中获取用户信息, 注意返回的 Result,如果出现异常,过期等信息不会直接抛出, 将返回到R 中
* 2、此方法可在业务代码中判断当前是否登录( Result.getCode == 200 表示登录/ 其他情况表示未登录)
* 示例代码:
* Result jwtUserR = JwtUtil.getJwtUserR(request, response);
* Boolean isLogin = jwtUserR.getCode().equals(ResultType.SYS_SUCCESS.getValue()) ? true : false;
* if (isLogin) {
* String userId = jwtUserR.getData().getUserId();
* }
*
*
* @param request
* @param response
* @return
*/
public static Result getJwtUserR(HttpServletRequest request, HttpServletResponse response) {
try {
// 判断是否传递tokne
String jwtToken = request.getHeader(TOKEN);
if (jwtToken == null || jwtToken == "") {
return Result.error(ResultType.GATEWAY_NO_TOKEN);
}
Claims claims = Jwts.parser().setSigningKey(APPSECRET_KEY).parseClaimsJws(jwtToken).getBody();
return Result.success(getClaimsJwtUser(claims));
} catch (ExpiredJwtException ex) {
/**
* jwt-token (expiration) 过期处理方法(1-超过总有效期未登录过,token过期 2-在总有效期内,刷新jwt-tokne 延长总有效期--需前端更新token)
*/
Claims claims = ex.getClaims();
JwtUser jwtUser = getClaimsJwtUser(claims);
// 只获取用户信息,直接返回
if (response == null) {
return Result.success(jwtUser);
}
// 如果不是只获取用户信息, 判断token是否在真实有效期内,超过了返回token过期提示
long expiredTime = Long.parseLong(claims.get(EXPIRED_TIME).toString());
if (System.currentTimeMillis() > expiredTime) {
return Result.error(ResultType.GATEWAY_LOGIN_EXPIRED);
}
// 管理端获取每次刷新获取新的刷新时间, 如果没有设值,使用登录设置的默认时间
if (jwtUser.getType().equals(userType[0])) {
SysConfigVO configByCode = XjCacheUtil.findConfigByCode(ConfigCacheKey.MANAGE_LOGIN_EXPIRATION);
jwtUser.setExpiration(Integer.parseInt(configByCode.getContent()));
}
createToken(jwtUser, response);
log.debug("token 已刷新");
return Result.success(jwtUser);
} catch (SignatureException ex) {
/**
* JWT签名与本地计算签名不匹配
*/
return Result.error(ResultType.GATEWAY_JWT_SIGN_ERROR);
} catch (Exception e) {
/**
* JWT解析错误
*/
return Result.error(ResultType.GATEWAY_JWT_PARSING_ERROR);
}
}
/**
* 获取用户信息的具体方法
*
* @param claims
* @return
*/
private static JwtUser getClaimsJwtUser(Claims claims) {
// user 信息
String deflaterJwtUser = claims.get(AUTH_USER).toString();
//JwtUser jwtUser = JsonUtil.parseEntity(DeflaterUtils.unzipString(deflaterJwtUser), JwtUser.class);
return JSON.parseObject(deflaterJwtUser, JwtUser.class);
}
}