1.jwt 生产token 也可以用MD5 生成token
@Component
@Slf4j
public class JwtUtil {
/**
* 过期时间
*/
private static String accessTokenExpireTime;
/**
* JWT认证加密私钥(Base64加密)
*/
private static String encryptJWTKey;
/**
* 解决@Value不能修饰static的问题
*/
@Value("${accessTokenExpireTime}")
public void setAccessTokenExpireTime(String accessTokenExpireTime) {
JwtUtil.accessTokenExpireTime = accessTokenExpireTime;
}
@Value("${encryptJWTKey}")
public void setEncryptJWTKey(String encryptJWTKey) {
JwtUtil.encryptJWTKey = encryptJWTKey;
}
/**
* @Title: verify @Description: TODO(检验token是否有效) @param: @param
* token @param: @return @return: boolean @throws
*/
public static boolean verify(String token) {
try {
// 通过token获取密码
String secret = getUserId(token) + Base64ConvertUtil.encode(encryptJWTKey) + getMobile(token);
// 进行二次加密
Algorithm algorithm = Algorithm.HMAC256(secret);
// 使用JWTVerifier进行验证解密
JWTVerifier verifier = JWT.require(algorithm).build();
verifier.verify(token);
return true;
} catch (UnsupportedEncodingException e) {
log.error("JWTToken认证解密出现UnsupportedEncodingException异常:" + e.getMessage());
return false;
}
}
/**
* @Title: sign @Description: TODO(生成签名) @param: @param mobile @param: @param
* password @param: @param currentTimeMillis @param: @return @return:
* String @throws
*/
public static String getToken(String userId, String mobile, String currentTimeMillis) {
try {
// 使用私钥进行加密
String secret = userId + Base64ConvertUtil.encode(encryptJWTKey) + mobile;
// 设置过期时间:根据当前时间计算出过期时间。 此处过期时间是以毫秒为单位,所以乘以1000。
Date date = new Date(System.currentTimeMillis() + Long.parseLong(accessTokenExpireTime) * 1000);
// 对私钥进行再次加密
Algorithm algorithm = Algorithm.HMAC256(secret);
// 生成token 附带account信息
String token = JWT.create().withClaim(CommonConstant.MOBILE, mobile).withClaim(CommonConstant.USER_ID, userId).withClaim(CURRENT_TIME_MILLIS, currentTimeMillis)
.withExpiresAt(date).sign(algorithm);
return token;
} catch (UnsupportedEncodingException e) {
log.error("JWTToken加密出现UnsupportedEncodingException异常:" + e.getMessage());
throw new RuntimeException("JWTToken加密出现UnsupportedEncodingException异常:" + e.getMessage());
}
}
/**
* @Title: getClaim @Description:
* TODO(获取token中的信息就是withClaim中设置的值) @param: @param token @param: @param
* claim:sign()方法中withClaim设置的值 @param: @return @return: String @throws
*/
public static String getClaim(String token, String claim) {
try {
// 对token进行解码获得解码后的jwt
DecodedJWT jwt = JWT.decode(token);
// 获取到指定的claim,如果是其他类型返回null
return jwt.getClaim(claim).asString();
} catch (JWTDecodeException e) {
log.error("解密Token中的公共信息出现JWTDecodeException异常:" + e.getMessage());
throw new RuntimeException("解密Token中的公共信息出现JWTDecodeException异常:" + e.getMessage());
}
}
/**
* token 获取用户userID
*
* @param token
* @return
*/
public static String getUserId(String token) {
String userId = getClaim(token, CommonConstant.USER_ID);
return userId;
}
/**
* token 获取手机号码
*
* @param token
* @return
*/
public static String getMobile(String token) {
String mobile = getClaim(token, CommonConstant.MOBILE);
return mobile;
}
/**
* token 获取手机号码
*
* @param token
* @return
*/
public static String getCurrentTimeMillis(String token) {
String currentTimeMillis = getClaim(token, CommonConstant.CURRENT_TIME_MILLIS);
return currentTimeMillis;
}
}
登录获取token 并且设置Redis 失效时间
private String getToken(Long userId, String mobile) { String currentTimeMillis = String.valueOf(System.currentTimeMillis()); RedisUtil.setEx(RedisKeyPrefix.SFC_REFRESH_TOKEN + mobile, currentTimeMillis, Long.parseLong(refreshTokenExpireTime), TimeUnit.SECONDS); return JwtUtil.getToken(String.valueOf(userId), mobile, currentTimeMillis); }
新增拦截器,从redis中获取失效时间和所携带token 比对,是否已失效
Object currentTimeMillisRedis = RedisUtil.get(RedisKeyPrefix.SFC_REFRESH_TOKEN + mobile);
// 获取AccessToken时间戳,与RefreshToken的时间戳对比
if (JwtUtil.getCurrentTimeMillis(token).equals(currentTimeMillisRedis.toString())) {
/
}
@Slf4j
public class AuthorizationInterceptor implements HandlerInterceptor {
@Value("${refreshTokenExpireTime}")
private String refreshTokenExpireTime;
@Autowired
private IUserService userService;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object object) throws Exception {
String requestURI = request.getRequestURI();
//对于不用进行验证的接口直接放行
if (ReleaseAddressUtil.confirm(requestURI)) {
return true;
}
String token = request.getHeader(CommonConstant.AUTHORIZATION);
if (token == null) {
// 获取当前请求类型
String httpMethod = request.getMethod();
// 获取当前请求URI
log.info("当前请求 {} Authorization属性(Token)为空 请求类型 {}", requestURI, httpMethod);
// mustLoginFlag = true 开启任何请求必须登录才可访问
this.response401(request, response, "请先登录");
return false;
}
String mobile = null;
String userId = null;
try {
mobile = JwtUtil.getMobile(token);
userId = JwtUtil.getUserId(token);
} catch (Exception e) {
e.printStackTrace();
log.info(e.getMessage());
this.response401(request,response,"token错误!");
return false;
}
if (StringUtils.isEmpty(mobile)) {
this.response401(request, response, "token错误!");
return false;
}
if (StringUtils.isEmpty(userId)) {
this.response401(request, response, "token错误!");
return false;
}
User user = userService.getByUserId(Long.valueOf(userId));
if (user == null) {
this.response401(request, response, "账号不存在!");
return false;
}
if (user.getStatus() != null && CommonConstant.DISABLE.equals(user.getStatus())) {
this.response401(request, response, "帐号已被锁定,禁止登录!");
return false;
}
try {
if (JwtUtil.verify(token) && RedisUtil.hasKey(RedisKeyPrefix.SFC_REFRESH_TOKEN + mobile)) {
Object currentTimeMillisRedis = RedisUtil.get(RedisKeyPrefix.SFC_REFRESH_TOKEN + mobile);
// 获取AccessToken时间戳,与RefreshToken的时间戳对比
if (JwtUtil.getCurrentTimeMillis(token).equals(currentTimeMillisRedis.toString())) {
UserInfo userInfo = new UserInfo();
userInfo.setId(user.getId());
userInfo.setUserId(user.getUserId());
userInfo.setMobile(user.getMobile());
userInfo.setNickname(user.getNickname());
UserContext.set(userInfo);
return true;
}
}
} catch (Exception e) {
// 认证出现异常,传递错误信息msg
String msg = e.getMessage();
this.response401(request, response, msg);
return false;
}
return false;
}
@Override
public void postHandle(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse,
Object o, ModelAndView modelAndView) {
}
@Override
public void afterCompletion(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse,
Object o, Exception e) {
//关闭threadLocal
UserContext.remove();
}
/**
* 缺少权限内部转发至401处理
*
* @param request
* @param response
* @param msg
*/
private void response401(ServletRequest request, ServletResponse response, String msg) {
HttpServletRequest req = (HttpServletRequest) request;
try {
req.getRequestDispatcher("/app/user/login/unauthorized?message=" + msg).forward(request, response);
} catch (Exception e) {
log.error("未授权登录{}", e);
}
}
}