1.传统的登录认证形式
1.用户登录时,将客户端发来的登录信息保存到服务端的session作用域中
2.然后这份信息在响应时传递给浏览器,并保存为cookie(含有JSESSIONID)
3下次识别根据JESSIONID来查找对应的session
2.使用jwt (json web token)
1.组成形式 Header.Payload.Signature
- Header(标头) 通常由两部分组成,一个是类型(typ),一个是所用的签名算法(alg),一般两个都是默认
- {
"alg": "HS256",
"typ": "jwt"
}
上述是原始状态,但响应到浏览器上会使用Base64编码 - Payload(有效载荷): 里面一般含有不敏感的数据,类似于
{
"id": "1212",
"name": "admin:
} - Signature(签名)由被Base64编码的Header和Payload 再加上自定义的密钥,由Header中的指定算法所得
2,整合springboot
(1).引入依赖
<dependency> <!--引入jwt-->
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.4.0</version>
</dependency>
(2).生成jwt的token
@Test
void jwtCreate() {
//设置token的过期时间
Date date = new Date(System.currentTimeMillis() + 100 * 1000);
//设置token的Header,一般默认,可以不用设置 (默认形式:jwt,默认算法:HMAC256)
Map<String, Object> map = new HashMap<>();
//获得token
String token = JWT.create()
.withHeader(map) //设置Header
.withClaim("userId", 13) //设置Payload 非敏感值
.withClaim("userName", "admin")
.withExpiresAt(date) //设置过期时间
.sign(Algorithm.HMAC256("@312ewe")); //通过Header规定的算法,传入自定义的密钥
System.out.println(token);
}
(3)验证token
@Test
void jwtVerify() {
//根据相同的密钥和算法创建一个jwt验证器
JWTVerifier verifier = JWT.require(Algorithm.HMAC256("@312ewe")).build();
//用验证器进行验证,得到已解码的jwt
DecodedJWT decodedJwt = verifier.verify("自己构造的token(令牌)");
//通过已解码的jwt取出Payload
System.out.println(decodedJwt.getClaim("userId").asInt());
System.out.println(decodedJwt.getClaim("userName").asString());
}
(4)构造JwtUtils简化使用
public class JwtUtils {
//设置默认时间
public final static long EXPIRE_TIME = 30 * 60 * 1000;
//设置密钥
public final static String SECRET= "@qwq><<ghj";
/**
* 获得token签名
* @param map
* @return
*/
public static String getToken(Map<String, String> map) {
//获得jwt构造器
JWTCreator.Builder builder = JWT.create();
//builder.withHeader() 一般默认,不需要修改
//设置Payload
map.forEach((k,v) -> {
builder.withClaim(k,v);
});
//设置过期时间
builder.withExpiresAt(new Date(System.currentTimeMillis() +EXPIRE_TIME));
//设置密钥,获得token(令牌)
String token =builder.sign(Algorithm.HMAC256(SECRET));
return token;
}
/**
* 验证token是否合法
* @param token 前端传来的令牌
* @return 已解码的jwt
*/
public static DecodedJWT verify(String token) {
//获得jwt注册器
JWTVerifier verifier = JWT.require(Algorithm.HMAC256(SIGN)).build();
return verifier.verify(token);
}
}
(5)设置拦截器
public class JwtInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//一般token放在请求头中
String token = request.getHeader("token");
HashMap<String, Object> map = new HashMap<>();
try{
//使用JwtUtils验证token的合法性
DecodedJWT decodedJWT = JwtUtils.verify(token);
//认证成功,进行放行
return true;
}catch (SignatureVerificationException e){
map.put("status", false);
map.put("msg", "签名验证异常");
}catch (AlgorithmMismatchException e){
map.put("status", false);
map.put("msg", "算法不匹配异常");
}catch (TokenExpiredException e){
map.put("status", false);
map.put("msg", "令牌过期异常");
}catch (InvalidClaimException e){
map.put("status", false);
map.put("msg", "失效的payload异常");
}catch (Exception e) {
map.put("status", false);
map.put("msg", "其他异常");
}
//map数据转换成json
String json = new ObjectMapper().writeValueAsString(map);
response.setContentType("application/json;charset=UTF-8");
response.getWriter().println(json);
return false;
}
}
(6)加入拦截器
@Configuration
public class MyConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new JwtInterceptor())
.addPathPatterns("/**") //一般拦截所有请求
.excludePathPatterns("/user/**"); //不拦截与用户有关的注册请求
}
}