JWT(JSON Web Token)是一种用于在各方之间作为 JSON 对象安全传输信息的开放标准(RFC 7519)。它是自包含的,既可以被验证,也可以被信任,因为它是通过数字签名的。JWT 在许多现代应用中用于身份验证和授权。
JWT 的结构
JWT 由三部分组成:Header(头部)、Payload(负载)、Signature(签名)。每部分使用 Base64Url 编码,并用点号(.)分隔。
- Header:- 包含令牌类型(JWT)和签名算法(如 HMAC SHA256 或 RSA)。
{"alg":"HS256","typ":"JWT"}
- Payload:- 包含声明(claims),即实体(通常是用户)及附加数据。标准声明包括
iss
(签发者)、exp
(过期时间)、sub
(主题)等。{"sub":"1234567890","name":"John Doe","iat":1516239022}
- Signature:- 用于验证令牌的发送方及数据完整性。将编码后的 Header 和 Payload 通过指定算法进行签名。
HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
JWT 的工作流程
- 客户端登录:用户使用其凭据登录,服务器验证身份后生成 JWT,并将其返回给客户端。
- 客户端存储 JWT:客户端将 JWT 存储在本地存储、cookie 或其他安全位置。
- 客户端请求资源:客户端在每个请求的 HTTP 头部添加 JWT(通常在
Authorization: Bearer <token>
)。 - 服务器验证 JWT:服务器验证 JWT 的签名和有效性(如过期时间)。验证通过后,服务器处理请求并返回相应的数据。
Spring Security 与 JWT 集成
Spring Security 提供了与 JWT 集成的强大支持。以下是一个简单的示例,展示如何使用 Spring Security 和 JWT 进行身份验证和授权。
依赖
在
pom.xml
中添加必要的依赖:
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.1</version></dependency>
配置类
创建一个配置类,配置 Spring Security 和 JWT 验证。
@EnableWebSecuritypublicclassWebSecurityConfigextendsWebSecurityConfigurerAdapter{@Overrideprotectedvoidconfigure(HttpSecurity http)throwsException{
http.csrf().disable().authorizeRequests().antMatchers("/login").permitAll().anyRequest().authenticated().and().addFilter(newJWTAuthenticationFilter(authenticationManager())).addFilter(newJWTAuthorizationFilter(authenticationManager()));}@BeanpublicBCryptPasswordEncoderbCryptPasswordEncoder(){returnnewBCryptPasswordEncoder();}}
JWT 工具类
创建一个工具类用于生成和验证 JWT。
publicclassJWTUtil{privatestaticfinalStringSECRET_KEY="your_secret_key";publicstaticStringgenerateToken(Authentication auth){returnJwts.builder().setSubject(auth.getName()).setExpiration(newDate(System.currentTimeMillis()+864_000_000))// 10 days.signWith(SignatureAlgorithm.HS512,SECRET_KEY.getBytes()).compact();}publicstaticClaimsgetClaims(String token){returnJwts.parser().setSigningKey(SECRET_KEY.getBytes()).parseClaimsJws(token).getBody();}publicstaticbooleanvalidateToken(String token){try{Jwts.parser().setSigningKey(SECRET_KEY.getBytes()).parseClaimsJws(token);returntrue;}catch(JwtException|IllegalArgumentException e){returnfalse;}}}
认证过滤器
创建一个过滤器用于处理登录认证。
publicclassJWTAuthenticationFilterextendsUsernamePasswordAuthenticationFilter{privateAuthenticationManager authenticationManager;publicJWTAuthenticationFilter(AuthenticationManager authenticationManager){this.authenticationManager = authenticationManager;}@OverridepublicAuthenticationattemptAuthentication(HttpServletRequest req,HttpServletResponse res)throwsAuthenticationException{try{User creds =newObjectMapper().readValue(req.getInputStream(),User.class);return authenticationManager.authenticate(newUsernamePasswordAuthenticationToken(
creds.getUsername(),
creds.getPassword(),newArrayList<>()));}catch(IOException e){thrownewRuntimeException(e);}}@OverrideprotectedvoidsuccessfulAuthentication(HttpServletRequest req,HttpServletResponse res,FilterChain chain,Authentication auth)throwsIOException,ServletException{String token =JWTUtil.generateToken(auth);
res.addHeader("Authorization","Bearer "+ token);}}
授权过滤器
创建一个过滤器用于处理请求授权。
publicclassJWTAuthorizationFilterextendsBasicAuthenticationFilter{publicJWTAuthorizationFilter(AuthenticationManager authManager){super(authManager);}@OverrideprotectedvoiddoFilterInternal(HttpServletRequest req,HttpServletResponse res,FilterChain chain)throwsIOException,ServletException{String header = req.getHeader("Authorization");if(header ==null||!header.startsWith("Bearer ")){
chain.doFilter(req, res);return;}UsernamePasswordAuthenticationToken authentication =getAuthentication(req);SecurityContextHolder.getContext().setAuthentication(authentication);
chain.doFilter(req, res);}privateUsernamePasswordAuthenticationTokengetAuthentication(HttpServletRequest request){String token = request.getHeader("Authorization");if(token !=null){String user =JWTUtil.getClaims(token.replace("Bearer ","")).getSubject();if(user !=null){returnnewUsernamePasswordAuthenticationToken(user,null,newArrayList<>());}returnnull;}returnnull;}}
总结
JWT 提供了一种简洁而强大的方式来进行身份验证和授权,特别适用于分布式系统和微服务架构。Spring Security 通过其强大的扩展机制,使得与 JWT 的集成变得非常简单和高效。通过了解和应用这些技术,开发者可以构建出安全、可靠的现代 Web 应用。
版权归原作者 傲雪凌霜,松柏长青 所有, 如有侵权,请联系我们删除。