Ausgabe
Ich habe gerade ein Projekt erhalten, das ich warten muss, und ich muss Unterstützung für ein zusätzliches Authentifizierungsschema in einem Ressourcenserver hinzufügen. So etwas wie ein normales Authentication: Bearer <jwt.token>
, um ein benutzerdefiniertes zu verwenden: Authentication: Custom <other.jwt.token>
. Beide sollten unterschiedlich funktionieren und gehandhabt werden.
Ja, ich weiß, dass Spring mit mehreren Anbietern umgehen kann, ich weiß, dass ich einen ReactiveAuthenticationManager verwenden kann, aber ich stecke fest, wie ich mit dem Custom
Präfix für das undurchsichtige Token umgehen soll.
Nur um es klar zu stellen, ich brauche beide, um zu funktionieren – und natürlich anders gehandhabt zu werden:
GET /
Authorization: Bearer x.y.z
und
GET /
Authorization: Custom a.b.c
Wenn möglich, möchte ich auch die Liste der unterstützten Authentifizierungsprotokolle im WWW-Authorization
Header (dh Bearer, Custom
) zurückgeben.
Irgendwelche Hinweise? Googeln zeigt mich nur auf normales Zeug, mit Bearer und was auch immer ich versuche, lehnt Spring mich automatisch mit 401 ab (Token wird natürlich nicht behandelt).
Vielen Dank.
Lösung
Was ich getan habe:
- Ich habe verschiedene implementiert
ReactiveAuthenticationManager
, eine für jedes Protokoll, das ich brauchte. So etwas wieBearerReactiveAuthenticationManager
undCustomReactiveAuthenticationManager
und machte sie@Components
; ServerSecurityContextRepository
Ich habe auch beide Authentifizierungsmanager aus dem vorherigen Punkt implementiert und injiziert. Im Körper hatte ich so etwas wie:
@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();
}
}
Und meine SecurityConfig-Bean sah so aus:
@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();
}
}
Beantwortet von – dcg
Antwort geprüft von – Clifford M. (FixError Volunteer)