返回
解决分布式系统数据存储难题!从session转向JWT
后端
2023-05-01 18:37:20
从 Session 到 JWT:迈向更安全的认证
在构建现代 Web 应用程序时,认证是至关重要的,它能确保只有授权用户才能访问受保护的资源。在早期,Session 是用于保存用户状态和会话信息的常用方法,但随着分布式系统和跨域认证的兴起,Session 的局限性逐渐显现。因此,JSON Web Token(JWT)应运而生,它提供了一种更安全、更可靠的认证方式。
Session 的弊端
Session 存在几个明显的缺陷:
- 无法跨域认证: Session 依赖于 cookie,而 cookie 无法跨越不同的域。这对于构建跨域应用程序或实现单点登录 (SSO) 来说是个问题。
- 服务器资源消耗大: Session 信息存储在服务器的物理内存中,随着并发用户数量的增加,内存消耗将大幅增加。
- 安全性差: Session 信息通常以明文形式存储,容易被窃取和篡改。
JWT 的优势
JWT 是一种基于 JSON 的令牌,由头部、有效负载和签名组成。它具有以下优点:
- 跨域认证: JWT 可以跨域传递,非常适合构建跨域应用程序或实现 SSO。
- 安全性高: JWT 使用数字签名对头部和有效负载进行签名,确保令牌的完整性和真实性。
- 易于使用: JWT 是一种基于 JSON 的开放标准,易于生成、验证和解析。
如何在 Spring Boot 中使用 JWT
在 Spring Boot 应用程序中使用 JWT 非常简单。以下是步骤:
- 添加依赖项: 在项目 pom.xml 文件中添加 Spring Security 和 JWT 依赖项:
<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: 在 Spring Security 配置类中配置 JWT:
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private MyUserDetailsService userDetailsService;
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/login", "/register").permitAll()
.anyRequest().authenticated()
.and()
.addFilterBefore(new JWTAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
.addFilterAfter(new JWTAuthorizationFilter(), UsernamePasswordAuthenticationFilter.class);
}
}
- 生成和验证 JWT:
- 在 JWTAuthenticationFilter 中生成 JWT:
public class JWTAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
public JWTAuthenticationFilter() {
super("/login");
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
String username = request.getParameter("username");
String password = request.getParameter("password");
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
if (userDetails == null) {
throw new BadCredentialsException("Username or password is incorrect");
}
if (!passwordEncoder.matches(password, userDetails.getPassword())) {
throw new BadCredentialsException("Username or password is incorrect");
}
String jwt = Jwts.builder()
.setSubject(userDetails.getUsername())
.setExpiration(new Date(System.currentTimeMillis() + 3600 * 1000))
.signWith(SignatureAlgorithm.HS512, "secret")
.compact();
return new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
}
}
- 在 JWTAuthorizationFilter 中验证 JWT:
public class JWTAuthorizationFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws IOException, ServletException {
String token = request.getHeader("Authorization");
if (token != null && token.startsWith("Bearer ")) {
try {
Jwts.parser()
.setSigningKey("secret")
.parseClaimsJws(token.substring(7));
} catch (Exception e) {
throw new BadCredentialsException("Invalid token");
}
}
filterChain.doFilter(request, response);
}
}
结论
使用 JWT 进行认证比 Session 更安全、更可靠、更易于跨域使用。通过在 Spring Boot 应用程序中集成 JWT,您可以构建更强大、更安全的 Web 应用程序。
常见问题解答
- JWT 和 Session 有什么区别? JWT 是基于 token 的,而 Session 是基于 cookie 的。JWT 可以跨域,而 Session 不能。JWT 更安全,因为它们使用数字签名来验证令牌的完整性和真实性。
- JWT 的安全性如何? JWT 使用数字签名来验证令牌的完整性和真实性。只要密钥保持机密,JWT 就非常安全。
- 如何使用 JWT 实现单点登录? 要使用 JWT 实现单点登录,您需要在所有应用程序之间共享一个秘密密钥。然后,您可以在一个应用程序中生成一个 JWT,并在其他应用程序中验证它。
- JWT 的缺点是什么? JWT 的主要缺点是它们可以被窃取和重用。但是,可以通过采用适当的安全措施来缓解此风险。
- JWT 的未来是什么? JWT 是一种流行且成熟的认证方法。随着 Web 应用程序变得更加分布式和跨域,预计 JWT 将继续发挥重要作用。