[英]Webflux JWT Authorization not working fine
我正在學習 Spring 響應式上下文 (webflux) 中有關 JWT 的教程。
令牌生成工作正常,但是當我使用帶有bearer
的Authorization
時, 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
執行。
我不確定你想用resignTokenMemory
做resignTokenMemory
,所以我會讓你自己修復它:
public Boolean validateToken(String token) {
return !isTokenExpired(token) && resignTokenMemory.check(token);
}
另一件事,您的令牌僅有效 28,8 秒,為了測試存在理由,我建議您expiraiton * 1000
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.