JWT = JSON Web Token,它是通过JSON格式组织必要的数据,将数据记录在票据(Token)上,并且,结合一定的算法,使得这些数据会被加密,然后在网络上传输,服务器端收到此数据后,会先对此数据进行解密,从而得到票据上记录的数据(JSON数据),从而识别用户的身份,或者处理相关的数据。
要使用JWT,需要添加相关的依赖项,可以实现生成JWT、解析JWT的框架较多,目前,主流的JWT框架可以是jjwt:
io.jsonwebtoken jjwt 0.9.1
JWT的组成部分:
- Header(头) { “alg”: 算法, “typ”: “jwt” }
- Payload(载荷) 通常包含Claims(自定义数据)和过期时间
- Signature(签加粗样式名) 由算法和密钥(secret key)这2部分组成
Jwt的测试
public class JwtTests {
// 密钥
String secretKey = "fgfdsfadsfadsafdsafdsfadsfadsfdsafdasfdsafdsafdsafds4rttrefds";
@Test
public void testGenerateJwt() {
// Claims
Map claims = new HashMap<>();
claims.put("id", 9527);
claims.put("name", "星星");
// JWT的组成部分:Header(头),Payload(载荷),Signature(签名)
String jwt = Jwts.builder()
// Header:指定算法与当前数据类型
// 格式为: { "alg": 算法, "typ": "jwt" }
.setHeaderParam(Header.CONTENT_TYPE, "HS256")
.setHeaderParam(Header.TYPE, Header.JWT_TYPE)
// Payload:通常包含Claims(自定义数据)和过期时间
.setClaims(claims)
.setExpiration(new Date(System.currentTimeMillis() + 5 * 60 * 1000))
// Signature:由算法和密钥(secret key)这2部分组成
.signWith(SignatureAlgorithm.HS256, secretKey)
// 打包生成
.compact();
// eyJjdHkiOiJIUzI1NiIsInR5cCI6IkpXVCIsImFsZyI6IkhTMjU2In0.eyJuYW1lIjoi5pif5pifIiwiaWQiOjk1MjcsImV4cCI6MTY1NTM2NzMwMn0.qBBHearv8iHPNjtDGtO2ci_-KAL4CALHnwzaG_ljsQg
System.out.println(jwt);
}
@Test
public void testParseJwt() {
String jwt = "eyJjdHkiOiJIUzI1NiIsInR5cCI6IkpXVCIsImFsZyI6IkhTMjU2In0.eyJuYW1lIjoi5pif5pifIiwiaWQiOjk1MjcsImV4cCI6MTY1NTM2NzMwMn0.qBBHearv8iHPNjtDGtO2ci_-KAL4CALHnwzaG_ljsQg";
Claims claims = Jwts.parser().setSigningKey(secretKey).parseClaimsJws(jwt).getBody();
Object id = claims.get("id");
Object name = claims.get("name");
System.out.println(" + id);
System.out.println("name=" + name);
}
}
当JWT数据过期时,异常信息例如:
io.jsonwebtoken.ExpiredJwtException: JWT expired at 2022-06-16T15:47:57Z. Current time: 2022-06-16T16:08:32Z, a difference of 1235869 milliseconds. Allowed clock skew: 0 milliseconds.
当JWT解析失败(数据有误)时,异常信息例如:
io.jsonwebtoken.MalformedJwtException: Unable to read JSON value: {"cty"�"HS256","typ":"JWT","alg":"HS256"}
当生成JWT和解析JWT的密钥不一致时,异常信息例如:
io.jsonwebtoken.SignatureException: JWT signature does not match locally computed signature. JWT validity cannot be asserted and should not be trusted.
要在Spring Security中使用JWT,至少需要:
-
不能让Spring Security按照原有模式来处理登录(原有模式中,登录成功后,自动装用户信息存储到Session中,且跳转页面),需要
-
需要自动装配AuthenticationManager对象
- 使得SecurityConfiguration配置类继承自WebSecurityConfigurerAdapter类,重写其中的方法,在此方法中直接调用父级方法即可,并在此方法上添加@Bean注解
-
@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
// 禁用防跨域攻击
http.csrf().disable();
// URL白名单
String[] urls = {
"/admins/login"
};
// 配置各请求路径的认证与授权
http.authorizeRequests() // 请求需要授权才可以访问
.antMatchers(urls) // 匹配一些路径
.permitAll() // 允许直接访问(不需要经过认证和授权)
.anyRequest() // 匹配除了以上配置的其它请求
.authenticated(); // 都需要认证
}
}



