First of all, the following part is obsolete, https://docs.spring.io/spring-security/reference/servlet/authorization/expression-based.html#el-access-web-path-variables for .access() method does not support a String anymore. I guess it must be updated to mirror previous section example that uses a WebExpressionAuthorizationManager()

But trying to reproduce it with WebExpressionAuthorizationManager does not work anyway, because the default expression handler is now DefaultHttpSecurityExpressionHandler instead of DefaultWebSecurityExpressionHandler and an exception jumps in with message "EL1057E: No bean resolver registered in the context to resolve access to bean".

But one cannot work it out with something like

WebExpressionAuthorizationManager authManager = new WebExpressionAuthorizationManager("@webSecurity.check(authentication,request)");
authManager.setExpressionHandler(new DefaultWebSecurityExpressionHandler());

because setExpressionHandler expects a SecurityExpressionHandler and DefaultWebSecurityExpressionHandler has FilterInvocation as type instead of RequestAuthorizationContext. the only built-in usabel one is therefore the default DefaultWebSecurityExpressionHandler.

So the whole section needs to be rewritten, and explain the equivalent modern way to achieve the legacy functionality, or statevery clear that SpEL expressions are not supported anymore out-of-the-box

Comment From: rwinch

Thank you for the report. You are right that the documentation needs fixed.

In the meantime, hopefully the following can help you and anyone experiencing this problem. SpEL is typically not necessary or preferred (SpEL is fast, but it does add overhead) with the addition of AuthorizationManager. You can use something like this now:

@Component
static class WebSecurity {
    public boolean checkUserId(Supplier<Authentication> authentication, String id) {
            return authentication.get().getName().equals(id);
    }
}

@Bean
public DefaultSecurityFilterChain springSecurityFilter(HttpSecurity http, WebSecurity webSecurity) throws Exception {
    http
        .authorizeHttpRequests(exchange -> exchange
            .requestMatchers("/user/{userId}/**").access((authentication, context) -> {
                    String userId = context.getVariables().get("userId");
                    boolean granted = webSecurity.checkUserId(authentication, userId);
                    return new AuthorizationDecision(granted);
                }
            )
            .anyRequest().authenticated()
        )
        .formLogin(withDefaults());
    return http.build();
}

If you really want to use SpEL you can use something like this:


@Component("webSecurity")
static class WebSecurity {
    public boolean checkUserId(Authentication authentication, String id) {
            return authentication.getName().equals(id);
    }
}

@Bean
public DefaultSecurityFilterChain springSecurityFilter(HttpSecurity http, ApplicationContext context) throws Exception {
    DefaultHttpSecurityExpressionHandler expressionHandler = new DefaultHttpSecurityExpressionHandler();
    expressionHandler.setApplicationContext(context);
    WebExpressionAuthorizationManager authorization = new WebExpressionAuthorizationManager("@webSecurity.checkUserId(authentication,#userId)");
    authorization.setExpressionHandler(expressionHandler);
    http
        .authorizeHttpRequests(exchange -> exchange
            .requestMatchers("/user/{userId}/**").access(authorization)
            .anyRequest().authenticated()
        )
        .formLogin(withDefaults());
    return http.build();
}

Comment From: nightswimmings

Thank you a lot @rwinch, very useful indeed!

Comment From: vinayvishwkarma

How can we use it for OAuth2WebSecurityExpressionHandler