Closed zaa4wz closed 3 weeks ago
The behavior shown in the tests was observed when running SpringBootTest; When running the application normally, I always got the same answer.
User Mvc UserA
User reactive null
User Mvc null
User reactive null
User Mvc UserB
User reactive null
I think I did not configure the application in the right way
After looking into the OAuth 2.0 Resource Server
library (SecurityReactorContextConfiguration, OAuth2ImportSelector, ServletBearerExchangeFilterFunction) I was finally able to access SecurityContext inside WebClient.
Is there an easier way to access SecurityContext inside WebClient?
Added changes:
@Configuration
@EnableWebSecurity
@Import(SecurityConfig.ReactiveSecurity.class)
public class SecurityConfig {
static final class ReactiveSecurity implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{
"org.springframework.security.config.annotation.web.configuration.SecurityReactorContextConfiguration"
};
}
}
}
public class SecurityUtils {
static final String SECURITY_CONTEXT_ATTRIBUTES = "org.springframework.security.SECURITY_CONTEXT_ATTRIBUTES";
public static Mono<User> getReactiveUser() {
return Mono.deferContextual(Mono::just)
.cast(Context.class)
.flatMap(SecurityUtils::getAuthentication)
.map(Authentication::getPrincipal)
.filter(User.class::isInstance)
.cast(User.class);
}
private static Mono<Authentication> getAuthentication(Context ctx) {
return Mono.justOrEmpty(getAttribute(ctx, Authentication.class));
}
private static <T> T getAttribute(Context ctx, Class<T> clazz) {
// NOTE: SecurityReactorContextConfiguration.SecurityReactorContextSubscriber adds this key
if (!ctx.hasKey(SECURITY_CONTEXT_ATTRIBUTES)) {
return null;
}
Map<Class<T>, T> attributes = ctx.get(SECURITY_CONTEXT_ATTRIBUTES);
return attributes.get(clazz);
}
}
Because ReactiveSecurityContextHolder
writes to reactor's Context
object, you will typically write it as part of the reactive stack that requires it:
this.webClient.get()...
.bodyToMono(...)
.contextWrite(ReactiveSecurityContextHolder.withAuthentication(authentication));
That said, if you are using WebClient
, then Spring Security ships with ExchangeFilterFunction
implementations for both context holders, meaning I'm not clear on why you need to propagate anyway.
Either way, I think it would be best at this point to move this question over to StackOverflow where we prefer to answer usage questions. Would you please post this question there and share the link here?
Describe the bug I am using Spring MVC to create a service and Spring WebFlux to use WebClient. WebClient uses JWT to authorize a request taken from the login user. For offline tasks, I am using a technical user with is authorized manually using SecurityContextHolder. After setting and removing a user using SecurityContextHolder, ReactiveSecurityContextHolder does not have the same state as SecurityContextHolder. In the following examples, I will try to explain exactly what I did.
Is there a better way to set ReactiveSecurityContextHolder?
To Reproduce dependacies
Utils functions:
Test 1:
Test 2:
Test 3:
Test 4:
Test 5:
Test 6:
Expected behavior If I am setting reactive security context correctly, I would expect the following behavior to work: