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

2025-05-29 0 63

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)

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

?

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.com/LarryDpk/pkslow-samples

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

原文链接:https://www.pkslow.com/archives/springboot-spring-security-jwt-webflux

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。

快网idc优惠网 建站教程 Springboot WebFlux集成Spring Security实现JWT认证的示例 https://www.kuaiidc.com/108253.html

相关文章

发表评论
暂无评论