SpringBoot安全实战:JWT认证与权限控制
在现代Web应用开发中,安全是不可忽视的核心环节。SpringBoot作为主流的Java开发框架,提供了强大的安全支持。而JWT(JSON Web Token)作为一种轻量级的认证机制,与Spring Security结合,能够高效实现用户认证与权限控制。本文将深入探讨如何在SpringBoot项目中实战JWT认证与权限控制。
一、JWT原理与优势
JWT是一种开放标准(RFC 7519),用于在网络应用环境间安全地传递声明(claims)。它由三部分组成:头部(Header)、载荷(Payload)和签名(Signature),三部分通过点号(.)连接,形成一个紧凑的字符串。
JWT的核心优势在于无状态性。传统的Session认证需要服务器存储用户状态,而JWT将用户信息编码在Token中,服务器无需存储,减轻了内存压力,特别适合分布式系统。同时,JWT支持跨域认证,便于前后端分离架构的实现。
二、环境搭建与依赖配置
首先,创建一个SpringBoot项目,添加必要的依赖。在`pom.xml`中引入Spring Security、JWT库以及数据库支持:
```xml
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-security
io.jsonwebtoken
jjwt-api
0.11.5
io.jsonwebtoken
jjwt-impl
0.11.5
runtime
io.jsonwebtoken
jjwt-jackson
0.11.5
runtime
org.springframework.boot
spring-boot-starter-data-jpa
mysql
mysql-connector-java
runtime
```
三、JWT工具类实现
创建JWT工具类,封装Token的生成与验证逻辑:
```java
@Component
public class JwtUtil {
private String secret = "your-secret-key"; // 实际项目中应从配置文件读取
private int expiration = 3600; // Token有效期,单位秒
public String generateToken(String username) {
return Jwts.builder()
.setSubject(username)
.setExpiration(new Date(System.currentTimeMillis() + expiration 1000))
.signWith(SignatureAlgorithm.HS512, secret)
.compact();
}
public boolean validateToken(String token, String username) {
String tokenUsername = getUsernameFromToken(token);
return (username.equals(tokenUsername) && !isTokenExpired(token));
}
public String getUsernameFromToken(String token) {
return Jwts.parser()
.setSigningKey(secret)
.parseClaimsJws(token)
.getBody()
.getSubject();
}
private boolean isTokenExpired(String token) {
Date expiration = Jwts.parser()
.setSigningKey(secret)
.parseClaimsJws(token)
.getBody()
.getExpiration();
return expiration.before(new Date());
}
}
```
四、用户认证与权限控制
1. 用户实体与数据库
```java
@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;
@Column(nullable = false)
private String role; // ROLE_USER, ROLE_ADMIN 等
// Getters and Setters
}
```
2. Security配置
配置Spring Security,定义认证和授权规则:
```java
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Autowired
private JwtUtil jwtUtil;
@Autowired
private UserDetailsService userDetailsService;
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeHttpRequests(authz -> authz
.requestMatchers("/api/auth/").permitAll()
.requestMatchers("/api/public/").permitAll()
.anyRequest().authenticated()
)
.sessionManagement(session -> session
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
)
.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
return http.build();
}
@Bean
public JwtAuthenticationFilter jwtAuthenticationFilter() {
return new JwtAuthenticationFilter(jwtUtil, userDetailsService);
}
}
```
3. JWT认证过滤器
```java
@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {
@Autowired
private JwtUtil jwtUtil;
@Autowired
private UserDetailsService userDetailsService;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
FilterChain chain) throws IOException, ServletException {
String token = extractToken(request);
if (token != null && jwtUtil.validateToken(token, getUsernameFromToken(token))) {
String username = jwtUtil.getUsernameFromToken(token);
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
UsernamePasswordAuthenticationToken authentication =
new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authentication);
}
chain.doFilter(request, response);
}
private String extractToken(HttpServletRequest request) {
String bearerToken = request.getHeader("Authorization");
if (bearerToken != null && bearerToken.startsWith("Bearer ")) {
return bearerToken.substring(7);
}
return null;
}
private String getUsernameFromToken(String token) {
return jwtUtil.getUsernameFromToken(token);
}
}
```
五、认证接口实现
创建认证Controller,提供登录和获取用户信息的接口:
```java
@RestController
@RequestMapping("/api/auth")
public class AuthController {
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private JwtUtil jwtUtil;
@Autowired
private UserDetailsService userDetailsService;
@PostMapping("/login")
public ResponseEntity login(@RequestBody LoginRequest loginRequest) {
try {
authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(loginRequest.getUsername(), loginRequest.getPassword())
);
UserDetails userDetails = userDetailsService.loadUserByUsername(loginRequest.getUsername());
String token = jwtUtil.generateToken(userDetails.getUsername());
return ResponseEntity.ok(new JwtResponse(token, userDetails.getUsername(), userDetails.getAuthorities()));
} catch (BadCredentialsException e) {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Invalid username or password");
}
}
@GetMapping("/user")
public ResponseEntity getUserInfo() {
String username = SecurityContextHolder.getContext().getAuthentication().getName();
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
return ResponseEntity.ok(new UserInfoResponse(userDetails.getUsername(), userDetails.getAuthorities()));
}
}
```
六、权限控制实战
在需要保护的接口上添加`@PreAuthorize`注解,实现细粒度的权限控制:
```java
@RestController
@RequestMapping("/api/admin")
@PreAuthorize("hasRole('ADMIN')")
public class AdminController {
@GetMapping("/users")
public List getAllUsers() {
// 只有具有ADMIN角色的用户才能访问
return userService.getAllUsers();
}
@PostMapping("/users")
public User createUser(@RequestBody User user) {
return userService.createUser(user);
}
}
```
七、总结
通过以上实战,我们构建了一个基于JWT的SpringBoot安全体系。JWT无状态的特性使其非常适合分布式系统,而Spring Security提供了强大的安全支持。在实际项目中,还需注意以下几点:
1. 密钥管理:JWT的secret应妥善保管,避免泄露。
2. Token刷新:可实现Token刷新机制,延长用户登录状态。
3. 日志记录:记录认证日志,便于安全审计。
4. HTTPS:生产环境必须使用HTTPS,防止Token被窃取。
通过合理运用JWT与Spring Security,能够有效保障Web应用的安全性,为用户提供可靠的服务。
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐


所有评论(0)