好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

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

1 简介

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

2 项目整合

引入必要的依赖:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

< 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。

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

@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)

         测试数据pact();

 

   }

 

   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测试数据maSeparatedStringToAuthorityList(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。

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

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。

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

@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,再返回给客户端。

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

@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测试数据/LarryDpk/pkslow-samples

以上就是Springboot WebFlux集成Spring Security实现JWT认证的示例的详细内容,更多关于Springboot WebFlux集成Spring Security的资料请关注其它相关文章!

原文链接:https://HdhCmsTestpkslow测试数据/archives/springboot-spring-security-jwt-webflux

查看更多关于Springboot WebFlux集成Spring Security实现JWT认证的示例的详细内容...

  阅读:27次