如何将AccessDecisionManager迁移为适配OAuth2WebSecurityExpressionHandler的AuthorizationManager
核心问题分析
原代码中使用的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
相关产品推荐
相关产品推荐

