基于 Spring Boot 实现用户身份验证与授权方案
在现代 Web 应用程序开发中,用户身份验证与授权是一个至关重要的功能。本文将介绍如何使用 Spring Boot 实现用户身份验证与授权功能,并提供完整的解决方案。
功能需求
- 用户可以使用用户名和密码进行登录。
- 只有授权用户才能访问受保护的资源。
- 支持基于角色的访问控制(RBAC)。
- 用户的密码需要加密存储。
- 提供 JWT 令牌机制,支持无状态身份验证。
技术选型
- Spring Boot:快速构建 Java Web 应用程序。
- Spring Security:提供身份验证和授权功能。
- JWT (JSON Web Token):用于无状态身份验证。
- Spring Data JPA:用于数据库操作。
- BCrypt:用于密码加密存储。
解决方案
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.11.5</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
2. 创建用户实体
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(unique = true, nullable = false)
private String username;
@Column(nullable = false)
private String password;
@Enumerated(EnumType.STRING)
private Role role;
// Getters and Setters
}
3. 定义用户角色
public enum Role {
ROLE_USER,
ROLE_ADMIN
}
4. 创建用户存储库
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
Optional<User> findByUsername(String username);
}
5. 实现用户服务
@Service
public class UserService implements UserDetailsService {
@Autowired
private UserRepository userRepository;
@Autowired
private PasswordEncoder passwordEncoder;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findByUsername(username)
.orElseThrow(() -> new UsernameNotFoundException("User not found"));
return new org.springframework.security.core.userdetails.User(
user.getUsername(),
user.getPassword(),
Collections.singleton(new SimpleGrantedAuthority(user.getRole().name()))
);
}
public User registerUser(String username, String password, Role role) {
User user = new User();
user.setUsername(username);
user.setPassword(passwordEncoder.encode(password));
user.setRole(role);
return userRepository.save(user);
}
}
6. 配置 Spring Security
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Autowired
private UserService userService;
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeHttpRequests(auth -> auth
.requestMatchers("/admin/**").hasRole("ADMIN")
.requestMatchers("/user/**").hasRole("USER")
.requestMatchers("/auth/**").permitAll()
.anyRequest().authenticated()
)
.sessionManagement(sess -> sess.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.userDetailsService(userService)
.httpBasic();
return http.build();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
7. 生成 JWT 令牌
@Component
public class JwtUtil {
private final String SECRET_KEY = "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, SECRET_KEY)
.compact();
}
public String extractUsername(String token) {
return Jwts.parser()
.setSigningKey(SECRET_KEY)
.parseClaimsJws(token)
.getBody()
.getSubject();
}
}
8. 认证控制器
@RestController
@RequestMapping("/auth")
public class AuthController {
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private JwtUtil jwtUtil;
@PostMapping("/login")
public ResponseEntity<?> login(@RequestBody AuthRequest request) {
authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(request.getUsername(), request.getPassword())
);
String token = jwtUtil.generateToken(request.getUsername());
return ResponseEntity.ok(new AuthResponse(token));
}
}
9. 运行与测试
启动 Spring Boot 应用后,可以使用 Postman 测试 API:
- 发送
POST /auth/login请求,获取 JWT 令牌。 - 使用 JWT 令牌访问受保护的 API。
总结
本文介绍了如何使用 Spring Boot 和 Spring Security 实现用户身份验证与授权功能,并通过 JWT 令牌实现无状态身份验证。这种方案适用于大多数 Web 应用,能够提供安全、高效的用户管理功能。