要想知道什么是jwt,就要先知道什么是session,可以这样理解session,处于安全问题,有一些数据需要保存在服务端,服务端根据客户端的sessionId可以识别到它的session,然后进行数据的处理。
session一般存储一些简单,并且比较重要的信息,例如用户id,用户登录状态,权限等。
注意,如果用户禁用了cookie,那么session也就无法使用,因为session使用cookie中携带的唯一id才能在服务器中找到
jwt全程是json web token。是由用户以用户名、密码登录,服务端验证后,会生成一个token,返回给客户端,客户端在下次访问的过程中携带这个token,服务端责每次验证这个token。
总而言之,如果使用了分布式,切只能在session和jwt里面选的时候,就一定要选jwt。
包含令牌的类型和使用的签名算法
{
"alg":"HS625", // 签名算法
"type":"JWT" // 令牌类型
}
将请求头进行base64加密就构成了第一部分
荷载就是装载数据的地方,包含声明(有关用户实体和其他数据的声明),使用Base64进行编码,
可以把payload荷载想象成session的数据,session虽然存放在服务器内存,也要防止一些意外,比如有工作人员监守自盗盗取密码,因此,session里面不可以存放敏感信息
{
"username": "zhangsan",
"dataAuth": "beijing"
}
将header和payload经过base64加密后的数据经过加盐后进行二次加密。
盐值仅仅保存在服务器端,不能泄露,如果泄露容易导致客户端自己签发token,例如:即使没有经过登录步骤,知道用户名username,用自己签发token去访问一些数据权限敏感的数据。
implementions('io.jsonwebtoken:jjwt:0.7.0')
# token私钥,储存在只有签发和解析token的服务端
jwt.secret=123456
# 过期时间,单位为毫秒,这里是24*60*60*1000,24小时内有效
jwt.expire=86400000
@ConfigurationProperties(prefix = "jwt")
@Component
@Data
public class JwtConfig {
private String secret;
private long expire;
/**
* 签发jwt
*
* @param user
* @return
*/
public String createJWT(User user) {
Date date = new Date();
Date expireDate = new Date(date.getTime() + expire);
Map<String, Object> claims = new HashMap<>();
claims.put("name", user.getUsername());
claims.put("id", user.getId());
String jwt = Jwts.builder()
// 设置装载内容
.setClaims(claims)
// 签发时间
.setIssuedAt(date)
// 过期时间
.setExpiration(expireDate)
// jwt主体,用来存放jwt的所有人,可以存用户id或者角色id
.setSubject(user.getName())
.compact();
return jwt;
}
/**
* 解析JWT
*
* @param jwt
* @return
*/
public Claims parseJWT(String jwt) {
Claims claims = Jwts.parser().setSigningKey(secret).parseClaimsJwt(jwt).getBody();
return claims;
}
}
@RequestMapping("login")
public Map<String, Object> login(@RequestParam(name = "name") String name, @RequestParam(name = "passWord") String passWord) {
User user = userService.findByUsernameAndPassword(name, passWord);
if (null == user ) {
throw new ControllerException("501", "用户名或密码错误");
}
String token = jwtConfig.createJWT(user);
map.put("token", token);
return map;
}
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Resource
private LoginInterceptor loginInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(loginInterceptor).addPathPatterns("/**");
}
}
@Component
public class LoginInterceptor extends HandlerInterceptorAdapter {
@Resource
private JwtConfig jwtConfig;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
String url = request.getRequestURI();
// 如果包含login,则直接去验证用户名密码,不需要去验证token,可以利用这里设置白名单
if (url.contains("/login")) {
return true;
}
String token = request.getHeader(jwtConfig.getHeader());
if (StringUtils.isEmpty(token)) {
token = request.getParameter(jwtConfig.getHeader());
}
if (null == token || token.isEmpty()) {
return false;
}
Claims claims = jwtConfig.parseJWT(token);
String userName = claims.get("name", String.class);
request.setAttribute("userName", subject);
return true;
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
return true;
}
}