我刚刚有一个需要维护的项目,我需要在资源服务器中添加对额外身份验证方案的支持。除了常规Authentication: Bearer <jwt.token>
之外,还可以使用自定义的:Authentication: Custom <other.jwt.token>
.两者都应该以不同的方式工作和处理。
是的,我知道 spring 可以处理多个提供程序,我知道我可以使用 ReactiveAuthenticationManager,但我被困在如何处理不透明令牌的Custom
前缀上。
为了明确一点,我需要同时工作 - 当然,也需要以不同的方式处理:
GET /
Authorization: Bearer x.y.z
和
GET /
Authorization: Custom a.b.c
如果可能的话,我还想在标头中返回支持的身份验证协议列表WWW-Authorization
(即Bearer, Custom
)。
有什么提示吗?谷歌搜索只向我指出常规的东西,使用 Bearer 和我尝试的任何东西,spring 会自动拒绝我 401(当然,令牌不处理)。
谢谢。
我做了什么:
- 我实现了不同的
ReactiveAuthenticationManager
,我需要的每个协议一个。像BearerReactiveAuthenticationManager
和CustomReactiveAuthenticationManager
这样的东西,使它们@Components
; - 我还实现了
ServerSecurityContextRepository
并从上一点注入了两个身份验证管理器。在身体里,我有这样的东西:
@Override
public Mono<SecurityContext> load(ServerWebExchange serverWebExchange) {
ServerHttpRequest request = serverWebExchange.getRequest();
String authHeader = request.getHeaders().getFirst(HttpHeaders.AUTHORIZATION);
if (authHeader.startsWith("Bearer ")) {
String authToken = authHeader.substring(7);
Authentication auth = new UsernamePasswordAuthenticationToken(authToken, authToken);
return this.bearerReactiveAuthenticationManager.authenticate(auth)
.map(SecurityContextImpl::new);
} else if (authHeader.startsWith("Custom ")) { {
String authToken = authHeader.substring(7);
Authentication auth = new UsernamePasswordAuthenticationToken(authToken, authToken);
return this.customReactiveAuthenticationManager.authenticate(auth)
.map(SecurityContextImpl::new);
} else {
log.debug("Could not identify the authentication header");
return Mono.empty();
}
}
我的 SecurityConfig bean 看起来像这样:
@Configuration
@EnableWebFluxSecurity
@EnableReactiveMethodSecurity
@Slf4j
public class SecurityConfig {
private final ServerSecurityContextRepository serverSecurityContextRepository;
@Autowired
public SecurityConfig(ServerSecurityContextRepository serverSecurityContextRepository) {
this.serverSecurityContextRepository = serverSecurityContextRepository;
}
@Bean
public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
http
.csrf().disable()
.formLogin().disable()
.httpBasic().disable()
.logout().disable()
.securityContextRepository(serverSecurityContextRepository)
.exceptionHandling()
.authenticationEntryPoint((swe, e) -> Mono.fromRunnable(() -> swe.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED)))
.accessDeniedHandler((swe, e) -> Mono.fromRunnable(() -> swe.getResponse().setStatusCode(HttpStatus.FORBIDDEN)))
.and().authorizeExchange();
return http.build();
}
}