Spring Boot用户身份验证与授权方案

基于Spring Boot的用户身份验证与授权方案

在现代Web应用程序中,用户身份验证和授权是确保系统安全的关键部分。本文将探讨如何使用Spring Boot实现一个安全、高效的用户身份验证和授权系统。

功能需求

  1. 用户可以注册、登录,并获取访问令牌(JWT)。
  2. 只有经过身份验证的用户才能访问受保护的API。
  3. 不同角色的用户具有不同的访问权限(如管理员和普通用户)。
  4. 令牌过期机制及刷新功能。

技术选型

  • Spring Boot:简化Java Web应用开发。
  • Spring Security:提供身份验证和授权功能。
  • JWT(JSON Web Token):用于无状态身份验证。
  • Spring Data JPA + MySQL:存储用户信息。

方案设计

1. 数据库设计

定义用户表(User)和角色表(Role),用户与角色是多对多关系。

@Entity
@Table(name = "users")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String username;
    private String password;
    
    @ManyToMany(fetch = FetchType.EAGER)
    @JoinTable(
        name = "user_roles",
        joinColumns = @JoinColumn(name = "user_id"),
        inverseJoinColumns = @JoinColumn(name = "role_id")
    )
    private Set<Role> roles;
}
2. 用户注册与密码加密

使用Spring Security的BCryptPasswordEncoder进行密码加密存储。

@Service
public class UserService {
    @Autowired
    private UserRepository userRepository;
    @Autowired
    private PasswordEncoder passwordEncoder;

    public User registerUser(String username, String password) {
        User user = new User();
        user.setUsername(username);
        user.setPassword(passwordEncoder.encode(password));
        return userRepository.save(user);
    }
}
3. JWT 令牌生成与解析

使用jjwt库生成和验证JWT令牌。

@Component
public class JwtUtil {
    private String secretKey = "mySecretKey";

    public String generateToken(String username) {
        return Jwts.builder()
            .setSubject(username)
            .setIssuedAt(new Date())
            .setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60))
            .signWith(SignatureAlgorithm.HS256, secretKey)
            .compact();
    }

    public String extractUsername(String token) {
        return Jwts.parser()
            .setSigningKey(secretKey)
            .parseClaimsJws(token)
            .getBody()
            .getSubject();
    }
}
4. Spring Security 配置

配置Spring Security,使其支持JWT身份验证。

@EnableWebSecurity
public class SecurityConfig {
    @Autowired
    private JwtFilter jwtFilter;

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http.csrf().disable()
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/auth/login", "/auth/register").permitAll()
                .anyRequest().authenticated()
            )
            .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
            .addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class);
        return http.build();
    }
}
5. 用户登录接口

用户登录后返回JWT令牌。

@RestController
@RequestMapping("/auth")
public class AuthController {
    @Autowired
    private AuthenticationManager authenticationManager;
    @Autowired
    private JwtUtil jwtUtil;

    @PostMapping("/login")
    public ResponseEntity<?> login(@RequestBody LoginRequest request) {
        authenticationManager.authenticate(
            new UsernamePasswordAuthenticationToken(request.getUsername(), request.getPassword())
        );
        String token = jwtUtil.generateToken(request.getUsername());
        return ResponseEntity.ok(new AuthResponse(token));
    }
}

总结

本文介绍了如何使用Spring Boot、Spring Security和JWT实现用户身份验证与授权。通过JWT令牌机制,我们可以实现无状态的安全认证,提高系统的可扩展性和安全性。