You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将AccessDecisionManager迁移为适配OAuth2WebSecurityExpressionHandler的AuthorizationManager

迁移Spring Security AccessDecisionManager到AuthorizationManager(适配OAuth2表达式处理器)

核心问题分析

原代码中使用的OAuth2WebSecurityExpressionHandler实现的是SecurityExpressionHandler<FilterInvocation>,而新的WebExpressionAuthorizationManager要求的是SecurityExpressionHandler<RequestAuthorizationContext>,两者类型不兼容,导致无法直接替换。解决思路是通过自定义适配类,将RequestAuthorizationContext转换为FilterInvocation,委托给原有的OAuth2表达式处理器完成逻辑。

解决方案代码实现

1. 自定义表达式处理器适配器

创建适配RequestAuthorizationContext的表达式处理器,内部委托给OAuth2WebSecurityExpressionHandler:

@Component
public class OAuth2RequestAuthorizationExpressionHandler implements SecurityExpressionHandler<RequestAuthorizationContext> {

    private final OAuth2WebSecurityExpressionHandler delegateHandler;

    public OAuth2RequestAuthorizationExpressionHandler(ApplicationContext applicationContext) {
        this.delegateHandler = new OAuth2WebSecurityExpressionHandler();
        this.delegateHandler.setApplicationContext(applicationContext);
    }

    @Override
    public EvaluationContext createEvaluationContext(Authentication authentication, RequestAuthorizationContext context) {
        // 将RequestAuthorizationContext转换为FilterInvocation
        FilterInvocation filterInvocation = new FilterInvocation(
                context.getRequest(),
                context.getResponse(),
                () -> null // 若无需执行后续过滤器链,可返回空实现
        );
        return this.delegateHandler.createEvaluationContext(authentication, filterInvocation);
    }

    @Override
    public SecurityExpressionOperations createSecurityExpressionRoot(Authentication authentication, RequestAuthorizationContext context) {
        FilterInvocation filterInvocation = new FilterInvocation(
                context.getRequest(),
                context.getResponse(),
                () -> null
        );
        OAuth2WebSecurityExpressionRoot expressionRoot = new OAuth2WebSecurityExpressionRoot(authentication, filterInvocation);
        // 同步原处理器的核心配置
        expressionRoot.setPermissionEvaluator(this.delegateHandler.getPermissionEvaluator());
        expressionRoot.setTrustResolver(this.delegateHandler.getTrustResolver());
        expressionRoot.setRoleHierarchy(this.delegateHandler.getRoleHierarchy());
        return expressionRoot;
    }
}

2. 构建AuthorizationManager

替代原有的AccessDecisionManager,使用DelegatingAuthorizationManager模拟UnanimousBased的一致通过逻辑:

@Bean
public AuthorizationManager<RequestAuthorizationContext> authorizationManager(OAuth2RequestAuthorizationExpressionHandler expressionHandler) {
    // 替换为你实际需要的权限表达式
    WebExpressionAuthorizationManager expressionAuthManager = new WebExpressionAuthorizationManager("hasAuthority('SCOPE_read')");
    expressionAuthManager.setExpressionHandler(expressionHandler);
    
    // 模拟原UnanimousBased的投票逻辑:所有授权条件需一致通过
    return DelegatingAuthorizationManager.unanimous(expressionAuthManager);
}

3. 在SecurityFilterChain中配置授权规则

将自定义的AuthorizationManager注入到HttpSecurity的授权配置中:

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http, AuthorizationManager<RequestAuthorizationContext> authorizationManager) throws Exception {
    http
        .authorizeHttpRequests(authConfig -> authConfig
            .anyRequest().access(authorizationManager)
        )
        // 保留你的OAuth2资源服务器配置
        .oauth2ResourceServer(oauth2 -> oauth2
            .jwt(jwt -> jwt.jwtAuthenticationConverter(jwtAuthenticationConverter()))
        );
    return http.build();
}

关键说明

  • 适配器类的核心是完成RequestAuthorizationContext到FilterInvocation的转换,复用原有的OAuth2表达式处理逻辑,无需重写权限判断代码。
  • DelegatingAuthorizationManager提供了多种投票策略:unanimous()对应原UnanimousBased,majority()对应AffirmativeBased,可根据原业务逻辑选择。
  • 如果需要多个授权条件(类似原代码中多个AccessDecisionVoter),可添加多个AuthorizationManager到DelegatingAuthorizationManager的参数列表中。

内容的提问来源于stack exchange,提问作者The_new_coder

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 14:47:38