下面是关于“Springboot WebFlux集成Spring Security实现JWT认证的示例”的完整攻略。
一、简介
在开始之前,先简单介绍一下SpringBoot和SpringSecurity。
SpringBoot:是Spring官方提供的一个快速开发框架,它能够极大地简化项目的搭建和配置,提高开发效率。
SpringSecurity:是Spring官方提供的一个安全框架,用于实现基于角色的授权和身份验证等安全功能。
本文将结合WebFlux和SpringSecurity,实现JWT认证功能的示例。
二、技术栈
- SpringBoot 2.0+
- Spring Security 5.0+
- WebFlux
- JWT
三、使用步骤
1.添加相关依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.0</version>
</dependency>
2.实现登录验证逻辑
首先实现一个类来封装用户登录信息:
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class LoginDTO {
private String username;
private String password;
}
然后,创建登录接口/api/login
,用于接收用户的登录信息,并进行身份验证:
@RestController
@RequestMapping("/api")
public class LoginController {
@PostMapping("/login")
public Mono<ResponseEntity<?>> login(@RequestBody LoginDTO loginDTO) {
//TODO: 1.进行身份认证
//TODO: 2.生成JWT并返回
return Mono.empty();
}
}
在进行身份认证之前我们需要实现自定义的UserDetailsService接口,并重写其中的loadUserByUsername方法,用于从数据库或其他地方查询用户的详细信息。
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
@Autowired
private UserRepository userRepository;
@Override
public Mono<UserDetails> findByUsername(String username) {
return userRepository.findByUsername(username)
.map(user -> User.withUsername(user.getUsername())
.password(user.getPassword())
.roles(user.getRoles())
.build())
.cast(UserDetails.class);
}
}
在上面实现的方式中,UserRepository是一个自定义的接口,用于查询用户名和密码等信息。
@Repository
public interface UserRepository {
Mono<User> findByUsername(String username);
}
接下来实现登录逻辑:
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private JwtConfig jwtConfig;
@Autowired
private UserDetailsService userDetailsService;
@PostMapping("/login")
public Mono<ResponseEntity<?>> login(@RequestBody LoginDTO loginDTO) {
return authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(loginDTO.getUsername(), loginDTO.getPassword()))
.map(authentication -> {
String token = jwtConfig.generateToken((UserDetails) authentication.getPrincipal());
return ResponseEntity.ok(Collections.singletonMap("token", token));
})
.defaultIfEmpty(ResponseEntity.status(HttpStatus.UNAUTHORIZED).build());
}
登录过程中通过调用AuthenticationManager
的authenticate
方法进行身份验证,并在验证成功后,生成Token返回给客户端。
这里通过JwtConfig
类,实现了JWT Token的生成和验证逻辑,其中generateToken
方法用于生成Token,validateToken
方法用于验证Token。
3.实现Token拦截器
添加一个Token拦截器来验证用户提交的Token是否合法,拦截器相关代码如下:
public class JwtTokenAuthenticationFilter extends OncePerRequestFilter {
@Autowired
private JwtConfig jwtConfig;
@Autowired
private UserDetailsService userDetailsService;
@Override
protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
try {
String authorizationHeader = httpServletRequest.getHeader(jwtConfig.getHeader());
if (StringUtils.isBlank(authorizationHeader) || !authorizationHeader.startsWith(jwtConfig.getTokenPrefix())) {
filterChain.doFilter(httpServletRequest, httpServletResponse);
return;
}
String token = authorizationHeader.replace(jwtConfig.getTokenPrefix(), "");
if (StringUtils.isNotBlank(token) && jwtConfig.validateToken(token)) {
Authentication authentication = new UsernamePasswordAuthenticationToken(jwtConfig.getUsername(token), null);
SecurityContextHolder.getContext().setAuthentication(authentication);
}
} catch (Exception e) {
logger.error("Failed to set user authentication in security context", e);
}
filterChain.doFilter(httpServletRequest, httpServletResponse);
}
}
4.配置SpringSecurity
配置SpringSecurity,并指定自定义的UserDetailsService。
@Configuration
@EnableWebFluxSecurity
public class SecurityConfig {
@Autowired
private JwtTokenAuthenticationFilter jwtTokenAuthenticationFilter;
@Autowired
private JwtConfig jwtConfig;
@Bean
public SecurityWebFilterChain securitygWebFilterChain(ServerHttpSecurity http) {
return http
.authorizeExchange()
.pathMatchers(HttpMethod.OPTIONS).permitAll()
.pathMatchers("/**").hasRole("USER")
.and()
.csrf().disable()
.httpBasic().disable()
.formLogin().disable()
.addFilterBefore(jwtTokenAuthenticationFilter, SecurityWebFiltersOrder.HTTP_BASIC)
.build();
}
@Bean
public ReactiveUserDetailsService reactiveUserDetailsService() {
return username -> jwtConfig.getUserDetails(username);
}
}
5.配置JwtConfig
配置JwtConfig,实现Token的生成和验证逻辑:
@Data
@ConfigurationProperties(prefix = "jwt")
public class JwtConfig {
private String secret;
private String tokenPrefix;
private String header;
public String generateToken(UserDetails userDetails) {
Map<String, Object> claims = new HashMap<>();
return Jwts.builder()
.setClaims(claims)
.setSubject(userDetails.getUsername())
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 10))
.signWith(SignatureAlgorithm.HS256, secret)
.compact();
}
public Boolean validateToken(String token) {
try {
Jwts.parser().setSigningKey(secret).parseClaimsJws(token);
return true;
} catch (SignatureException e) {
logger.error("Invalid JWT signature -> {}", e.getMessage());
} catch (MalformedJwtException e) {
logger.error("Invalid JWT token -> {}", e.getMessage());
} catch (ExpiredJwtException e) {
logger.error("Expired JWT token -> {}", e.getMessage());
} catch (UnsupportedJwtException e) {
logger.error("Unsupported JWT token -> {}", e.getMessage());
} catch (IllegalArgumentException e) {
logger.error("JWT claims string is empty -> {}", e.getMessage());
}
return false;
}
public String getUsername(String token) {
return Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody().getSubject();
}
public UserDetails getUserDetails(String username) {
return new User(username, "", Collections.singletonList(new SimpleGrantedAuthority("ROLE_USER")));
}
}
四、示例
这里提供两个参考示例:
示例一
基于SpringBoot的WebFlux和SpringSecurity实现JWT Token认证,Github:https://github.com/pkpk1234/springboot-webflux-websocket/tree/springboot-webflux-security-jwt-token
示例二
基于SpringBoot的WebFlux和SpringSecurity实现JWT Token认证,并且结合了实时多人聊天的场景,Github:https://github.com/WebCodeDream/spring-webflux-websocket-jwt-chatroom
通过这两个示例,可以更深入地理解SpringBoot WebFlux集成Spring Security实现JWT认证的流程和各组件之间的相互关系。
希望对你有所帮助。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Springboot WebFlux集成Spring Security实现JWT认证的示例 - Python技术站