我最新最全的文章都在南瓜慢说 www.pkslow.com,欢迎大家来喝茶!

1 简介

在之前的文章《Springboot集成Spring Security实现JWT认证》讲解了如何在传统的Web项目中整合Spring SecurityJWT,今天我们讲解如何在响应式WebFlux项目中整合。二者大体是相同的,主要区别在于Reactive WebFlux与传统Web的区别。

2 项目整合

引入必要的依赖:

<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>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>

2.1 JWT工具类

该工具类主要功能是创建、校验、解析JWT

@Component
public class JwtTokenProvider { private static final String AUTHORITIES_KEY = "roles"; private final JwtProperties jwtProperties; private String secretKey; public JwtTokenProvider(JwtProperties jwtProperties) {
this.jwtProperties = jwtProperties;
} @PostConstruct
public void init() {
secretKey = Base64.getEncoder().encodeToString(jwtProperties.getSecretKey().getBytes());
} public String createToken(Authentication authentication) { String username = authentication.getName();
Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
Claims claims = Jwts.claims().setSubject(username);
if (!authorities.isEmpty()) {
claims.put(AUTHORITIES_KEY, authorities.stream().map(GrantedAuthority::getAuthority).collect(joining(",")));
} Date now = new Date();
Date validity = new Date(now.getTime() + this.jwtProperties.getValidityInMs()); return Jwts.builder()
.setClaims(claims)
.setIssuedAt(now)
.setExpiration(validity)
.signWith(SignatureAlgorithm.HS256, this.secretKey)
.compact(); } public Authentication getAuthentication(String token) {
Claims claims = Jwts.parser().setSigningKey(this.secretKey).parseClaimsJws(token).getBody(); Object authoritiesClaim = claims.get(AUTHORITIES_KEY); Collection<? extends GrantedAuthority> authorities = authoritiesClaim == null ? AuthorityUtils.NO_AUTHORITIES
: AuthorityUtils.commaSeparatedStringToAuthorityList(authoritiesClaim.toString()); User principal = new User(claims.getSubject(), "", authorities); return new UsernamePasswordAuthenticationToken(principal, token, authorities);
} public boolean validateToken(String token) {
try {
Jws<Claims> claims = Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token); if (claims.getBody().getExpiration().before(new Date())) {
return false;
} return true;
} catch (JwtException | IllegalArgumentException e) {
throw new InvalidJwtAuthenticationException("Expired or invalid JWT token");
}
} }

2.2 JWT的过滤器

这个过滤器的主要功能是从请求中获取JWT,然后进行校验,如何成功则把Authentication放进ReactiveSecurityContext里去。当然,如果没有带相关的请求头,那可能是通过其它方式进行鉴权,则直接放过,让它进入下一个Filter

public class JwtTokenAuthenticationFilter implements WebFilter {

    public static final String HEADER_PREFIX = "Bearer ";

    private final JwtTokenProvider tokenProvider;

    public JwtTokenAuthenticationFilter(JwtTokenProvider tokenProvider) {
this.tokenProvider = tokenProvider;
} @Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
String token = resolveToken(exchange.getRequest());
if (StringUtils.hasText(token) && this.tokenProvider.validateToken(token)) {
Authentication authentication = this.tokenProvider.getAuthentication(token);
return chain.filter(exchange)
.subscriberContext(ReactiveSecurityContextHolder.withAuthentication(authentication));
}
return chain.filter(exchange);
} private String resolveToken(ServerHttpRequest request) {
String bearerToken = request.getHeaders().getFirst(HttpHeaders.AUTHORIZATION);
if (StringUtils.hasText(bearerToken) && bearerToken.startsWith(HEADER_PREFIX)) {
return bearerToken.substring(7);
}
return null;
}
}

2.3 Security的配置

这里设置了两个异常处理authenticationEntryPointaccessDeniedHandler

@Configuration
public class SecurityConfig { @Bean
SecurityWebFilterChain springWebFilterChain(ServerHttpSecurity http,
JwtTokenProvider tokenProvider,
ReactiveAuthenticationManager reactiveAuthenticationManager) { return http.csrf(ServerHttpSecurity.CsrfSpec::disable)
.httpBasic(ServerHttpSecurity.HttpBasicSpec::disable)
.authenticationManager(reactiveAuthenticationManager)
.exceptionHandling().authenticationEntryPoint(
(swe, e) -> {
swe.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return swe.getResponse().writeWith(Mono.just(new DefaultDataBufferFactory().wrap("UNAUTHORIZED".getBytes())));
})
.accessDeniedHandler((swe, e) -> {
swe.getResponse().setStatusCode(HttpStatus.FORBIDDEN);
return swe.getResponse().writeWith(Mono.just(new DefaultDataBufferFactory().wrap("FORBIDDEN".getBytes())));
}).and()
.securityContextRepository(NoOpServerSecurityContextRepository.getInstance())
.authorizeExchange(it -> it
.pathMatchers(HttpMethod.POST, "/auth/login").permitAll()
.pathMatchers(HttpMethod.GET, "/admin").hasRole("ADMIN")
.pathMatchers(HttpMethod.GET, "/user").hasRole("USER")
.anyExchange().permitAll()
)
.addFilterAt(new JwtTokenAuthenticationFilter(tokenProvider), SecurityWebFiltersOrder.HTTP_BASIC)
.build();
} @Bean
public ReactiveAuthenticationManager reactiveAuthenticationManager(CustomUserDetailsService userDetailsService,
PasswordEncoder passwordEncoder) {
UserDetailsRepositoryReactiveAuthenticationManager authenticationManager = new UserDetailsRepositoryReactiveAuthenticationManager(userDetailsService);
authenticationManager.setPasswordEncoder(passwordEncoder);
return authenticationManager;
}
}

2.4 获取JWT的Controller

先判断对用户密码进行判断,如果正确则返回对应的权限用户,根据用户生成JWT,再返回给客户端。

@RestController
@RequestMapping("/auth")
public class AuthController { @Autowired
ReactiveAuthenticationManager authenticationManager; @Autowired
JwtTokenProvider jwtTokenProvider; @PostMapping("/login")
public Mono<String> login(@RequestBody AuthRequest request) {
String username = request.getUsername();
Mono<Authentication> authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, request.getPassword())); return authentication.map(auth -> jwtTokenProvider.createToken(auth));
}
}

3 总结

其它与之前的大同小异,不一一讲解了。

代码请查看:https://github.com/LarryDpk/pkslow-samples


欢迎关注微信公众号<南瓜慢说>,将持续为你更新...

多读书,多分享;多写作,多整理。

Springboot WebFlux集成Spring Security实现JWT认证的更多相关文章

  1. Springboot集成Spring Security实现JWT认证

    我最新最全的文章都在南瓜慢说 www.pkslow.com,欢迎大家来喝茶! 1 简介 Spring Security作为成熟且强大的安全框架,得到许多大厂的青睐.而作为前后端分离的SSO方案,JWT ...

  2. spring boot rest 接口集成 spring security(2) - JWT配置

    Spring Boot 集成教程 Spring Boot 介绍 Spring Boot 开发环境搭建(Eclipse) Spring Boot Hello World (restful接口)例子 sp ...

  3. 「快学springboot」集成Spring Security实现鉴权功能

    Spring Security介绍 Spring Security是Spring全家桶中的处理身份和权限问题的一员.Spring Security可以根据使用者的需要定制相关的角色身份和身份所具有的权 ...

  4. Spring Boot 集成 Spring Security 实现权限认证模块

    作者:王帅@CodeSheep   写在前面 关于 Spring Security Web系统的认证和权限模块也算是一个系统的基础设施了,几乎任何的互联网服务都会涉及到这方面的要求.在Java EE领 ...

  5. spring security oauth2 jwt 认证和资源分离的配置文件(java类配置版)

    最近再学习spring security oauth2.下载了官方的例子sparklr2和tonr2进行学习.但是例子里包含的东西太多,不知道最简单最主要的配置有哪些.所以决定自己尝试搭建简单版本的例 ...

  6. SpringBoot 集成Spring security

    Spring security作为一种安全框架,使用简单,能够很轻松的集成到springboot项目中,下面讲一下如何在SpringBoot中集成Spring Security.使用gradle项目管 ...

  7. SpringBoot集成Spring Security

    1.Spring Security介绍 Spring security,是一个强大的和高度可定制的身份验证和访问控制框架.它是确保基于Spring的应用程序的标准 --来自官方参考手册 Spring ...

  8. spring boot rest 接口集成 spring security(1) - 最简配置

    Spring Boot 集成教程 Spring Boot 介绍 Spring Boot 开发环境搭建(Eclipse) Spring Boot Hello World (restful接口)例子 sp ...

  9. SpringBoot集成Spring Security(7)——认证流程

    文章目录 一.认证流程 二.多个请求共享认证信息 三.获取用户认证信息 在前面的六章中,介绍了 Spring Security 的基础使用,在继续深入向下的学习前,有必要理解清楚 Spring Sec ...

随机推荐

  1. 一款好用的数据血缘关系在线工具--SQLFlow

      l  数据血缘关系(data lineage) 数据血缘属于数据治理中的一个概念,是在数据溯源的过程中找到相关数据之间的联系,它是一个逻辑概念.数据治理中经常提到血缘分析,血缘分析是保证数据融合的 ...

  2. PTA 第三章 栈与队列

    一.判断题 1.若一个栈的输入序列为1,2,3,--,N,输出序列的第一个元素为i,则第j个输出的元素是j-i-1    (×)解析:应该是不确定的,不能保证数字出栈后不会再入栈 2.所谓" ...

  3. [知识路书]beta设计和计划

    [知识路书]beta设计和计划 一.需求再分析 根据用户反馈,是否发现之前的需求分析有偏差?为什么会出现这种偏差?beta阶段你们是否能真的分析清楚用户需求?如何做到? 根据alpha阶段的推广情况以 ...

  4. Java集合详解(五):Hashtable原理解析

    概述 本文是基于jdk8_271版本进行分析的. Hashtable与HashMap一样,是一个存储key-value的双列集合.底层是基于数组+链表实现的,没有红黑树结构.Hashtable默认初始 ...

  5. [Java] Spring 使用

    背景 JavaEE 应用框架 基于IOC和AOP的结构J2EE系统的框架 IOC(反转控制):即创建对象由以前的程序员自己new 构造方法来调用,变成了交由Spring创建对象,是Spring的基础 ...

  6. Docker------Linux安装Docker

    1.添加yum源 yum install epel-release –y yum clean all yum list 2.安装并运行Docker yum install docker-io –y s ...

  7. (代替人类)很多操作都在Settings里面。 5.安装第三方库

    2020-02-01 pycharm 使用教程 LingSmart关注 0.0842020.02.07 15:08:50字数 1,394阅读 680 实在无聊,就来学习吧.学习pycharm的使用教程 ...

  8. 013.Kubernetes认证授权

    一 Kubernetes认证系统介绍 1.1 访问控制 Kubernetes API的每个请求都会经过多阶段的访问控制之后才会被接受,这包括认证.授权以及准入控制(Admission Control) ...

  9. linux基础之权限管理

    本节内容 1. 权限类别 属主(owner) 属组(group) 其他人(other) 2. 查看权限 ls -l 十位: 第一位文件类型-,d,l, 3. 设置权限 chmod 选项 权限模式 fi ...

  10. docker启动失败如何查看容器日志

    docker启动失败如何查看容器日志 在使用docker的时候,在某些未知的情况下可能启动了容器,但是过了没几秒容器自动退出了.这个时候如何排查问题呢? 通常碰到这种情况无非就是环境有问题或者应用有问 ...