spring - Webflux JWT 授权无法正常工作

标签 spring security spring-security jwt spring-webflux

我正在关注tutorial关于 Spring 响应式(Reactive)上下文 (webflux) 中的 JWT。

token 生成工作正常,但是当我将Authorizationbearer一起使用时,授权不起作用

这是我所做的:

@EnableWebFluxSecurity
@EnableReactiveMethodSecurity
public class WebSecurityConfig{

    @Autowired private JWTReactiveAuthenticationManager authenticationManager;

    @Autowired private SecurityContextRepository securityContext;

    @Bean public SecurityWebFilterChain configure(ServerHttpSecurity http){

        return http.exceptionHandling()
        .authenticationEntryPoint((swe , e) -> {
            return Mono.fromRunnable(()->{
                System.out.println( "authenticationEntryPoint user trying to access unauthorized api end points : "+
                                    swe.getRequest().getRemoteAddress()+
                                    " in "+swe.getRequest().getPath());
                swe.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            });
        }).accessDeniedHandler((swe, e) -> {
            return Mono.fromRunnable(()->{
                System.out.println( "accessDeniedHandler user trying to access unauthorized api end points : "+
                                    swe.getPrincipal().block().getName()+
                                    " in "+swe.getRequest().getPath());
                swe.getResponse().setStatusCode(HttpStatus.FORBIDDEN);                    
            });
        })
        .and()
        .csrf().disable()
        .formLogin().disable()
        .httpBasic().disable()
        .authenticationManager(authenticationManager)
        .securityContextRepository(securityContext)
        .authorizeExchange()
        .pathMatchers(HttpMethod.OPTIONS).permitAll()
        .pathMatchers("/auth/login").permitAll()
        .anyExchange().authenticated()
        .and()
        .build();


    }

如您所见,我只想拒绝除登录或基于选项之外的所有未经授权的请求。

登录工作正常,我得到了一个 token 。

enter image description here

但是尝试注销(我自己实现的一个调整,使其成为全状态,因为我只是在学习)是行不通的。

这是我的注销 Controller :


@RestController
@RequestMapping(AuthController.AUTH)
public class AuthController {

    static final String AUTH = "/auth";

    @Autowired
    private AuthenticationService authService;

    @PostMapping("/login")
    public Mono<ResponseEntity<?>> login(@RequestBody AuthRequestParam arp) {

        String username = arp.getUsername();
        String password = arp.getPassword();

        return authService.authenticate(username, password);
    }

    @PostMapping("/logout")
    public Mono<ResponseEntity<?>> logout(@RequestBody LogoutRequestParam lrp) {

        String token = lrp.getToken();

        return authService.logout(token);
    }

}

注销请求如下:

enter image description here enter image description here

如上图所示,我相信我做得很好,但是我收到了错误日志消息:

authenticationEntryPoint user trying to access unauthorized api end points : /127.0.0.1:45776 in /auth/logout

这是我的安全上下文内容:


/**
 * we use this class to handle the bearer token extraction
 * and pass it to the JWTReactiveAuthentication manager so in the end 
 * we produce
 * 
 * simply said we extract the authorization we authenticate and 
 * depending on our implementation we produce a security context
 */

@Component
public class SecurityContextRepository implements ServerSecurityContextRepository {

    @Autowired
    private JWTReactiveAuthenticationManager authenticationManager;

    @Override
    public Mono<SecurityContext> load(ServerWebExchange swe) {

        ServerHttpRequest request = swe.getRequest();

        String authorizationHeaderContent = request.getHeaders().getFirst(HttpHeaders.AUTHORIZATION);

        if( authorizationHeaderContent !=null &&  !authorizationHeaderContent.isEmpty() &&  authorizationHeaderContent.startsWith("Bearer ")){

                String token = authorizationHeaderContent.substring(7);

                Authentication authentication = new UsernamePasswordAuthenticationToken(token, token);
                return this.authenticationManager.authenticate(authentication).map((auth) -> {
                    return new SecurityContextImpl(auth);
                });

        }

        return Mono.empty();
    }

    @Override
    public Mono<Void> save(ServerWebExchange arg0, SecurityContext arg1) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

}

我无法看到或发现我犯的任何问题或错误。哪里错了?

最佳答案

写法有区别

//Wrong
Jwts.builder()
   .setSubject(username)
   .setClaims(claims)

//Correct
Jwts.builder()
   .setClaims(claims)
   .setSubject(username)

确实,请查看 DefaultJwtBuilder 类中的 setSubject 方法:

@Override
public JwtBuilder setSubject(String sub) {
    if (Strings.hasText(sub)) {
        ensureClaims().setSubject(sub);
    } else {
        if (this.claims != null) {
            claims.setSubject(sub);
        }
    }
    return this;
}

当首先调用 setSubject(username) 时,ensureClaims() 会创建一个没有您的 DefaultClaims ,并且如果您调用 setClaims(声明) 先前的主题丢失了!这个 JWT 构建器是假的。

否则,您将在 JWTReactiveAuthenticationManager 中导入错误的 Role 类,您必须替换:

import org.springframework.context.support.BeanDefinitionDsl.Role;

import com.bridjitlearning.www.jwt.tutorial.domain.Role;

最后,由于 check(token)validateToken() 将始终返回 falseput 调用来得太晚了,你必须意识到这一点。您可以删除此检查,或者在调用检查方法之前移动 put 执行。

我不确定您想用 resignTokenMemory 做什么,所以我会让您自己修复它:

public Boolean validateToken(String token) {
    return !isTokenExpired(token) && resignTokenMemory.check(token);
}

另一件事,您的 token 有效期只有 28.8 秒,为了测试存在的理由,我建议您expiraiton * 1000

关于spring - Webflux JWT 授权无法正常工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56826021/

相关文章:

java - 在单元测试中与 KafkaEmbedded 一起使用时,@DirtiesContext 的行为是什么?

java - Maven 依赖项到底是什么?

java - 与 RabbitMQ 的模拟连接

android - 我为 Android In App Billing 的安全性付出了多少努力?

java - 强制 Spring 安全性在帐户状态标志之前检查凭据

java - spring boot应用是否支持OpenJDK

java - 将 JSP 生成的 Json 的 Java 字符串中的多个反斜杠替换为 HTML 实体

php - 如何防止 PHP 中的 SQL 注入(inject)?

security - 使用 PayPal 的 'Website Payments Pro' 存储信用卡信息?

java - 如何解决 Spring Security 配置问题