spring reactive + spring security
1. Security配置类(SecurityConfig.java
)
@Configuration
@EnableWebFluxSecurity
public class SecurityConfig {
@Bean
public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http, JwtFilter jwtFilter) {
http
.csrf().disable()
.authorizeExchange()
.anyExchange().authenticated()
.and()
.addFilterAt(jwtFilter, SecurityWebFiltersOrder.AUTHENTICATION);
return http.build();
}
@Bean
public ReactiveAuthenticationManager authenticationManager(UserDetailsService userDetailsService) {
return new ReactiveAuthenticationManagerAdapter(userDetailsService);
}
}
2. JWT过滤器(JwtFilter.java
)
@Component
public class JwtFilter implements WebFilter {
private final JwtUtil jwtUtil;
public JwtFilter(JwtUtil jwtUtil) {
this.jwtUtil = jwtUtil;
}
@Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
String authHeader = exchange.getRequest().getHeaders().getFirst("Authorization");
if (authHeader != null && authHeader.startsWith("Bearer ")) {
String token = authHeader.substring(7);
if (jwtUtil.validateToken(token)) {
// 检查Redis黑名单:若token存在则返回403
return chain.filter(exchange);
}
}
return Mono.error(new UnauthorizedException("Invalid token"));
}
}
3. JWT工具类(JwtUtil.java
)
@Component
public class JwtUtil {
private final String secretKey = "your-secret-key";
private final long expirationTime = 86400000; // 24小时
public String generateToken(String username) {
// 生成JWT token(实际实现需使用JJWT等库)
return "JWT_TOKEN_STRING";
}
public boolean validateToken(String token) {
// 验证token签名和过期时间(实际实现需解析JWT)
return true;
}
}
4. 服务层代码(AuthService.java
)
@Service
public class AuthService {
private final JwtUtil jwtUtil;
public AuthService(JwtUtil jwtUtil) {
this.jwtUtil = jwtUtil;
}
public String login(String username, String password) {
// 验证用户名密码(由UserDetailsService处理)
// 生成JWT token
return jwtUtil.generateToken(username);
}
public void logout(String token) {
// 将token存入Redis黑名单,设置过期时间为token剩余有效期
// 示例:redisTemplate.opsForValue().set(token, "blacklisted", remainingTime, TimeUnit.MILLISECONDS);
}
}
5. 控制器接口(AuthController.java
)
@RestController
@RequestMapping("/auth")
public class AuthController {
private final AuthService authService;
public AuthController(AuthService authService) {
this.authService = authService;
}
@PostMapping("/login")
public String login(@RequestBody Map<String, String> request) {
String username = request.get("username");
String password = request.get("password");
return authService.login(username, password);
}
@PostMapping("/logout")
public void logout(@RequestHeader("Authorization") String authHeader) {
String token = authHeader.substring(7); // 移除"Bearer "前缀
authService.logout(token);
}
@GetMapping("/isLogin")
public ResponseEntity<?> isLogin() {
return ResponseEntity.ok().build(); // 有有效token时返回200,否则由Security自动返回403
}
}