在现代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应用的安全性,为用户提供可靠的服务。

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐