返回

Spring Security + JWT打造坚不可摧的用户认证系统

后端

使用 Spring Security 和 JWT 在 Spring Boot 中实现用户认证:分步指南

在这个数字时代,应用程序的安全至关重要。用户希望他们的个人信息得到保护,而企业则有责任确保数据的机密性。在 Spring Boot 项目中,Spring Security 和 JWT(JSON Web Token)的组合提供了一种强大且灵活的方法来实现用户认证。

Spring Security 和 JWT

Spring Security 是一个广泛使用的安全框架,它提供开箱即用的认证、授权和防攻击功能。它与 Spring Boot 无缝集成,使安全配置变得轻而易举。

JWT 是一种轻量级的令牌,用于认证和授权。它通常用于单点登录 (SSO) 和移动应用程序,因为它允许在不存储用户敏感信息的情况下验证用户身份。

入门

1. 添加依赖项

首先,将以下依赖项添加到你的 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>

2. 配置 Spring Security

创建一个 SecurityConfig 类并扩展 WebSecurityConfigurerAdapter,如下所示:

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http
      .authorizeRequests()
      .antMatchers("/login").permitAll()
      .anyRequest().authenticated()
      .and()
      .formLogin()
      .loginPage("/login")
      .defaultSuccessUrl("/home")
      .permitAll();
  }

}

此配置允许对 /login 端点的匿名访问,并要求所有其他请求进行身份验证。它还使用基于表单的登录机制,在成功登录后重定向到 /home 端点。

3. 创建 JWT 令牌

创建一个 JwtUtils 类来生成和验证 JWT 令牌:

public class JwtUtils {

  private static final String SECRET_KEY = "my-secret-key";

  public static String generateToken(UserDetails userDetails) {
    return Jwts.builder()
      .setSubject(userDetails.getUsername())
      .setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 10))
      .signWith(SignatureAlgorithm.HS256, SECRET_KEY)
      .compact();
  }

  public static boolean validateToken(String token) {
    try {
      Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token);
      return true;
    } catch (Exception e) {
      return false;
    }
  }

}

SECRET_KEY 是一个用于对 JWT 进行数字签名的私钥,它应该是一个安全且保密的字符串。

4. 注册和登录

创建一个 UserController 类来处理用户注册和登录:

@RestController
public class UserController {

  @PostMapping("/register")
  public ResponseEntity<String> register(@RequestBody User user) {
    // ...省略代码...

    return ResponseEntity.ok("User registered successfully!");
  }

  @PostMapping("/login")
  public ResponseEntity<String> login(@RequestBody User user) {
    // ...省略代码...

    String token = JwtUtils.generateToken(userDetails);
    return ResponseEntity.ok(token);
  }

}

此类提供了两个端点:/register 用于注册新用户,/login 用于现有用户登录。成功登录后,系统将生成一个 JWT 令牌并将其作为响应的一部分返回。

5. 在请求中使用 JWT

现在你的应用程序可以生成 JWT 令牌,你需要在请求中使用它们来进行身份验证。可以通过在请求头中包含 Authorization 标头来实现,如下所示:

Authorization: Bearer <JWT_TOKEN>

在服务器端,你可以通过使用 @PreAuthorize 注解来保护端点,如下所示:

@PreAuthorize("hasRole('USER')")
@GetMapping("/api/user")
public User getUser() {
  // ...省略代码...
}

此注解确保只有具有 USER 角色的用户才能访问 /api/user 端点。

常见问题解答

1. JWT 中包含哪些信息?

JWT 通常包含以下信息:

  • 主题 (sub) :用户的标识符
  • 发行人 (iss) :令牌的发行者
  • 受众 (aud) :令牌的预期接收者
  • 过期时间 (exp) :令牌到期的时间
  • 签名 :用于验证令牌完整性的数字签名

2. 如何存储 JWT?

JWT 通常存储在客户端的会话存储(如 localStorage 或 cookie)中。

3. 如何保护 JWT?

  • 使用强壮的密钥对 JWT 进行数字签名
  • 将 JWT 存储在安全的地方,如 HttpOnly cookie 或加密本地存储中
  • 设置合理的过期时间以防止重放攻击
  • 考虑使用单点登录 (SSO)

4. JWT 与会话令牌有什么区别?

会话令牌将用户状态存储在服务器端,而 JWT 将用户状态存储在客户端。会话令牌可能更安全,但需要服务器端存储,而 JWT 更加轻量级且易于使用。

5. 什么是单点登录 (SSO)?

SSO 允许用户使用同一凭据登录到多个应用程序。JWT 经常用于 SSO,因为它可以轻松地在应用程序之间共享用户身份。

结论

使用 Spring Security 和 JWT,你可以轻松地在 Spring Boot 项目中实现安全的用户认证。这种组合提供了强大且灵活的方法,可满足各种安全需求。通过遵循本指南,你可以有效地保护你的应用程序免遭未经授权的访问,同时为用户提供无缝的登录体验。