返回

解决分布式系统数据存储难题!从session转向JWT

后端

从 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 非常简单。以下是步骤:

  1. 添加依赖项: 在项目 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>
  1. 配置 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);
    }
}
  1. 生成和验证 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 将继续发挥重要作用。