JWT令牌的认证与置换
令牌的产生是在具有登录服务的微服务上,而令牌的校验是在网关服务上对其进行校验
网关校验JWT
在网关过滤器IdentityAuthFilter中
/**
* 具体的过滤器规则
* @return
* @throws ZuulException
*/
@Override
public Object run() throws ZuulException {
System.out.println("执行过滤方法");
RequestContext requestContext = RequestContext.getCurrentContext();
HttpServletRequest request = requestContext.getRequest();
//从Http Header中,判断是否有authentication的存在
String authentication = request.getHeader("authentication");
if(StringUtils.hasLength(authentication)){
//有长度,暂时默认成功
System.out.println("进入到微服务");
System.out.println(authentication);
//当获取的令牌以后,Zuul需要对Token做一个身份识别
validateTokenLegal(authentication,requestContext);
}else{//如果没有长度,或者为NULL,设置响应失败(401)
handlerIllegalToken(requestContext,HttpStatus.UNAUTHORIZED.value(),
ResponseMsg.builder().code(10001).msg("未认证,请登录!").build());
}
return null;
}
/**
* 处理非常令牌
* @param requestContext
* @param status
* @param responseMsg
*/
public void handlerIllegalToken(RequestContext requestContext,int status,ResponseMsg responseMsg){
//不进入到下一步(route过滤器)
requestContext.setSendZuulResponse(false);
//设置响应数据
HttpServletResponse response = requestContext.getResponse();
response.setContentType("application/json");
response.setCharacterEncoding("utf-8");
requestContext.setResponse(response);
requestContext.setResponseStatusCode(status);
requestContext.setResponseBody(JSONObject.toJSONString
(responseMsg));
}
/**
* 用于识别Token令牌是否合法
* @param authentication
* @param requestContext
*/
private void validateTokenLegal(String authentication, RequestContext requestContext) {
//创建一个JWT的验证实例
JWTVerifier verifier = JWT.require(Algorithm.HMAC256(JWTUtil.SECURITY)).build();
try{
//该方法就是针对令牌做校验
DecodedJWT decodedJWT = verifier.verify(authentication);
//更新令牌
} catch (Exception e){
e.printStackTrace();
//令牌的算法错误
if(e instanceof AlgorithmMismatchException){
handlerIllegalToken(requestContext,HttpStatus.FORBIDDEN.value(),
ResponseMsg.builder().code(10003).msg("非法令牌,无法识别!").build());
//令牌已失效
}else if(e instanceof TokenExpiredException){
handlerIllegalToken(requestContext,HttpStatus.FORBIDDEN.value(),
ResponseMsg.builder().code(10004).msg("令牌已过期,请重新登录!").build());
//令牌是非法令牌
}else if(e instanceof SignatureVerificationException){
handlerIllegalToken(requestContext,HttpStatus.FORBIDDEN.value(),
ResponseMsg.builder().code(10005).msg("非法令牌,无法识别!").build());
}else{
handlerIllegalToken(requestContext,HttpStatus.FORBIDDEN.value(),
ResponseMsg.builder().code(10006).msg("未知错误!").build());
}
}
}
令牌的刷新
原理:前端发起的每次请求,后端都给它置换一个新的令牌的信息
/**
* 用于识别Token令牌是否合法
* @param authentication
* @param requestContext
*/
private void validateTokenLegal(String authentication, RequestContext requestContext) {
//创建一个JWT的验证实例
JWTVerifier verifier = JWT.require(Algorithm.HMAC256(JWTUtil.SECURITY)).build();
try{
//该方法就是针对令牌做校验
DecodedJWT decodedJWT = verifier.verify(authentication);
//更新令牌
Map<String,Object> claims = new HashMap<>();
String loginName = decodedJWT.getClaim("loginName").as(String.class);
claims.put("loginName",loginName);
String newToken = JWTUtil.createToken(claims);
//获取到响应对象
HttpServletResponse response = requestContext.getResponse();
response.setHeader("token",newToken);
} catch (Exception e){
e.printStackTrace();
//令牌的算法错误
if(e instanceof AlgorithmMismatchException){
handlerIllegalToken(requestContext,HttpStatus.FORBIDDEN.value(),
ResponseMsg.builder().code(10003).msg("非法令牌,无法识别!").build());
//令牌已失效
}else if(e instanceof TokenExpiredException){
handlerIllegalToken(requestContext,HttpStatus.FORBIDDEN.value(),
ResponseMsg.builder().code(10004).msg("令牌已过期,请重新登录!").build());
//令牌是非法令牌
}else if(e instanceof SignatureVerificationException){
handlerIllegalToken(requestContext,HttpStatus.FORBIDDEN.value(),
ResponseMsg.builder().code(10005).msg("非法令牌,无法识别!").build());
}else{
handlerIllegalToken(requestContext,HttpStatus.FORBIDDEN.value(),
ResponseMsg.builder().code(10006).msg("未知错误!
").build());
}
}
}
核心置换代码:
思考:
1、如果现在说所有的终端,当有1个终端在线时,其他终端就无法登陆?
答案:将Token统一位置存储,每个人单位时间针对所有的终端,只能存在一个终端的Token信息。
当然,上述的问题,需要配合Redis来实现
2、如果假设有人将你的Token获取到了,模拟你操作,后端如何保证敏感数据的安全性?
答案:短信验证,支付密码,短期令牌(1分钟),人脸识别
终端就无法登陆?
答案:将Token统一位置存储,每个人单位时间针对所有的终端,只能存在一个终端的Token信息。
当然,上述的问题,需要配合Redis来实现
2、如果假设有人将你的Token获取到了,模拟你操作,后端如何保证敏感数据的安全性?
答案:短信验证,支付密码,短期令牌(1分钟),人脸识别