1.前言
spring weblfux最大优势莫过于非阻塞带来的性能提升,认为其也会成为spring系列中最受欢迎的框架之一。
网络上大多数整合的文章还是依赖于Spring Boot +Security和用户名密码体系来组成验证模型。不太适合直接依赖于三方登录或微信登录的系统。
2.实现代码
POM.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
2.1 简单拦截器版本适用于面向用户端接口
@Configuration
public class JwtWebConfig implements WebFilter {
@Override
public Mono<Void> filter(ServerWebExchange serverWebExchange, WebFilterChain webFilterChain) {
ServerHttpRequest request= serverWebExchange.getRequest();
if(request.getPath().value().contains("login")){
return webFilterChain.filter(serverWebExchange);
}
ServerHttpResponse response=serverWebExchange.getResponse();
String authorization=request.getHeaders().getFirst("Authoriszation");
if(authorization == null || ! authorization.startsWith("Bearer ")){
return this.setErrorResponse(response,"未携带token");
}
String token=authorization.substring(7);
try {
serverWebExchange.getAttributes().put("user", Jwt.parseJwt(token));
}catch(Exception e) {
return this.setErrorResponse(response,e.getMessage());
}
return webFilterChain.filter(serverWebExchange);
}
protected Mono<Void> setErrorResponse(ServerHttpResponse response, String message){
response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
JSONObject jsonObject=new JSONObject();
jsonObject.put("status_code",500);
jsonObject.put("data",message);
return response.writeWith(Mono.just(response.bufferFactory().wrap(jsonObject.toString().getBytes())));
}
}
2.2 引入Spring Security 满足多用户多权限
AuthenticationManager.java
AuthenticationManager 负责校验 Authentication 对象。在 AuthenticationManager 的 authenticate 函数中,开发人员实现对 Authentication 的校验逻辑。
@Component
public class AuthenticationManager implements ReactiveAuthenticationManager {
@Override
public Mono<Authentication> authenticate(Authentication authentication) {
String authToekn=authentication.getCredentials().toString();
try {
Claims claims= Jwt.parseJwt(authToekn);
//todo 此处应该列出token中携带的角色表。
List<String> roles=new ArrayList();
roles.add("user");
Authentication authentication1=new UsernamePasswordAuthenticationToken(
claims.getId(),
null,
roles.stream().map(role->new SimpleGrantedAuthority(role)).collect(Collectors.toList())
);
return Mono.just(authentication1);
} catch (Exception e) {
throw new BadCredentialsException(e.getMessage());
}
}
}
SecurityContextRepository.java
此处用于从请求的信息中载入验证信息(即将header中的token包装成Authentication并进行验证)
@Component
public class SecurityContextRepository implements ServerSecurityContextRepository {
@Autowired
private AuthenticationManager authenticationManager;
@Override
public Mono<Void> save(ServerWebExchange serverWebExchange, SecurityContext securityContext) {
return Mono.empty();
}
@Override
public Mono<SecurityContext> load(ServerWebExchange serverWebExchange) {
ServerHttpRequest request = serverWebExchange.getRequest();
String authHeader = request.getHeaders().getFirst(HttpHeaders.AUTHORIZATION);
if (authHeader != null && authHeader.startsWith("Bearer ")) {
String authToken = authHeader.substring(7);
Authentication auth = null;
auth = new UsernamePasswordAuthenticationToken(authToken, authToken);
return this.authenticationManager.authenticate(auth).map(SecurityContextImpl::new);
} else {
return Mono.empty();
}
}
}
WebSecurityConfig.java
此处加在过滤链
@EnableWebFluxSecurity
@EnableReactiveMethodSecurity
public class WebSecurityConfig {
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private SecurityContextRepository securityContextRepository;
@Bean
public SecurityWebFilterChain securitygWebFilterChain(ServerHttpSecurity http) {
return http
.csrf().disable()
.formLogin().disable()
.httpBasic().disable()
.securityContextRepository(securityContextRepository)
.authorizeExchange()
.pathMatchers(HttpMethod.OPTIONS).permitAll()
.pathMatchers("/user/login").permitAll()
.anyExchange().authenticated()
.and().build();
}
}
3.Test
4.总结
这是一个极简版的实现。绝对相信签发出去的token。
优点
- 简单
- 性能高(验证不用查数据库同时也带来了一定的性能的提升。)
缺点
- 无法及时作废token。因为验证有效性和时效性。
更多关于jwt的使用,包括签发和验证可以百度或者看
https://www.jianshu.com/p/ac6cbad76dd6
引用参考