我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Springboot WebFlux集成Spring Security实现JWT认证的示例

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Springboot WebFlux集成Spring Security实现JWT认证的示例

1 简介

在之前的文章《Springboot集成Spring Security实现JWT认证》讲解了如何在传统的Web项目中整合Spring Security和JWT,今天我们讲解如何在响应式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的配置

这里设置了两个异常处理authenticationEntryPoint和accessDeniedHandler。


@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认证的示例的详细内容,更多关于Springboot WebFlux集成Spring Security的资料请关注编程网其它相关文章!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Springboot WebFlux集成Spring Security实现JWT认证的示例

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

【全网最细致】SpringBoot整合Spring Security + JWT实现用户认证

【全网最细致】SpringBoot整合Spring Security + JWT实现用户认证   登录和用户认证是一个网站最基本的功能,在这篇博客里,将介绍如何用SpringBoot整合Spring Security + JWT实现登录及用
2023-08-18

Spring Boot怎么集成JWT实现前后端认证

本文小编为大家详细介绍“Spring Boot怎么集成JWT实现前后端认证”,内容详细,步骤清晰,细节处理妥当,希望这篇“Spring Boot怎么集成JWT实现前后端认证”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知
2023-06-30

SpringBoot+SpringSecurity+JWT实现系统认证与授权示例

本文主要介绍了SpringBoot+SpringSecurity+JWT实现系统认证与授权示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
2022-11-13

springboot集成JWT实现身份认证(权鉴)的方法步骤

本文主要介绍了springboot集成JWT实现身份认证(权鉴)的方法步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
2023-05-16

SpringBoot集成Druid实现监控功能的示例代码

本文详细介绍了如何在SpringBoot应用程序中集成Druid以实现监控功能。Druid提供了一个控制台,用于监控数据库性能、SQL查询和系统资源。通过添加Druid依赖项、配置数据源、创建配置文件、启用控制台和运行应用程序,开发人员可以轻松启用Druid监控。Druid提供实时监控、SQL查询监控和系统资源监控等优点,帮助识别和优化数据库性能。
SpringBoot集成Druid实现监控功能的示例代码
2024-04-02

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录