簡體   English   中英

Webflux JWT 授權無法正常工作

[英]Webflux JWT Authorization not working fine

我正在學習 Spring 響應式上下文 (webflux) 中有關 JWT 的教程

令牌生成工作正常,但是當我使用帶有bearerAuthorization時, Authorization不起作用

這是我所做的:

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


    }

如您所見,我只想拒絕除登錄或基於選項的請求之外的所有未授權請求。

登錄工作正常,我得到了一個令牌。

在此處輸入圖片說明

但是嘗試注銷(由於我只是在學習,因此我自己實現了一個調整以使其狀態完整)是行不通的。

這是我的注銷控制器:


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

}

注銷請求如下:

在此處輸入圖片說明 在此處輸入圖片說明

如上圖所示,我相信我做得很好,但是我收到了錯誤日志消息:

authenticationEntryPoint 用戶試圖訪問未經授權的 api 端點:/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(claims)則先例主題丟失! 這個 JWT 構建器是假的。

否則,您在JWTReactiveAuthenticationManager導入了錯誤的 Role 類,您必須替換:

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

經過

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

最后同樣重要的是,由於check(token)validateToken()將始終返回false put期權來得太晚了,你必須意識到這一點。 要么刪除此檢查,要么在調用 check 方法之前移動put執行。

我不確定你想用resignTokenMemoryresignTokenMemory ,所以我會讓你自己修復它:

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

另一件事,您的令牌僅有效 28,8 秒,為了測試存在理由,我建議您expiraiton * 1000

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM