Token&JWT
token
前端请求后端时,后端需要保证这个请求来自受认可的用户,因此需要对用户进行认证。为避免频繁地使用与数据库交互以获取用户信息的手段来认证,在初次登陆后,后端为前端生成一个信息,前端在之后向后端发出请求时只需携带这个信息,后端通过判断该信息的合法性来判断是否允许该请求,以及认证用户,这个信息就是token
所以token并没有固定的实现方式,作为一种认证作用的工具,根据实际需求不同或开发者的习惯可以有不同的实现方式,只要能实现类似的认证作用即可
关于token的刷新机制
机制1:设置一个过期时间expire_time以及刷新时间refresh_time,刷新时间大于过期时间,当当前token存活时间达到过期时间时,可以凭借这个token去获得一个新的token;但如果存活时间大于刷新时间,就只能重新登陆来获取新的token。相当于就是,用户端拿着一个token,如果发出请求的频率较高(两次请求之间相隔不超过expire_time),那就没必要刷新token,一方面会影响到用户体验,一方面服务端这边也需要进行额外的生成token操作;而如果用户长时间没有发出新的请求,超出了refresh_time,那么对用户的信任就应降低,有必要刷新token
JWT
概述
JWT(json web token),是其中一种实现的规范,由三个部分组成:header
,payload
,signature
。header包含token的基本的通用信息,如加密所用算法,过期时间等;payload中可以携带如用户信息等其它的信息,例如可以把用户的账号密码作为payload的一部分;signature是对header,payload以及后端设定的盐值进行加密后组成的签证信息
代码示例
依赖
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.18.1</version>
</dependency>
JWT工具类
public class JwtUtil {
/**
* 自定义签名(盐值)
*/
private static final String SIGNATURE = "!Q@W#E$R";
/**
*生成token
* @param map 要放入payload的键值对数据
* @return java.lang.String
*/
public static String generateToken(Map<String,String> map){
Calendar calendar = Calendar.getInstance();
//设置15天为token过期时间
calendar.add(Calendar.DATE,15);
//创建builder
JWTCreator.Builder builder = JWT.create();
//将map中的键值对放入token的payload处
map.forEach(builder::withClaim);
//设置过期时间以及加密算法和签名
return builder.withExpiresAt(calendar.getTime())
//使用的加密算法一般都是这一个
.sign(Algorithm.HMAC256(SIGNATURE));
}
/**
*验证token,只要验证过程中有一步不通过该方法都会抛异常,因此不用过多处理
* @param token 前端请求携带的token
* @return com.auth0.jwt.interfaces.DecodedJWT
*/
public static DecodedJWT verify(String token){
return JWT.require(Algorithm.HMAC256(SIGNATURE)).build().verify(token);
}
}
整合拦截器
@Slf4j
public class JwtInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//从请求头获取token
String token = request.getHeader("token");
..............
try {
JwtUtil.verify(token);
return true;
}catch (SignatureVerificationException e){
log.error("token所使用的签名无效,[{}]",e.getMessage());
resultDto.put("msg","token所使用的签名无效");
}catch (TokenExpiredException e){
log.error("token已过期,[{}]",e.getMessage());
resultDto.put("msg","token已过期");
}catch (AlgorithmMismatchException e){
log.error("token所使用的算法不一致,[{}]",e.getMessage());
resultDto.put("msg","token所使用的算法不一致");
}catch (Exception e){
log.error("无效token![{}]",e.getMessage());
resultDto.put("msg","token无效");
}
response.getWriter().println(new ObjectMapper().writeValueAsString(....));
return false;
}
}
springMVC配置类
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
//在拦截器注册类中注册自定义的拦截器,以及要拦截的请求路径
registry.addInterceptor(new JwtInterceptor())
.addPathPatterns("/**");
}
}