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

Spring Security OAuth2替换默认过滤器实现安全上下文存储前设置用户角色

解决方案

问题原因

你遇到两个过滤器同时执行的核心原因是@EnableOAuth2Sso注解会自动向过滤器链注册默认的OAuth2ClientAuthenticationProcessingFilter,你使用addFilterAt只是在相同位置新增了自定义过滤器,并没有移除原有默认实例,因此两个过滤器会按顺序先后执行。

方案1:移除默认过滤器后添加自定义过滤器

直接在HttpSecurity配置中先移除默认的过滤器实例,再添加你的自定义过滤器即可,修改你的配置类代码:

@Override
protected void configure(HttpSecurity http) throws Exception {
    // 先移除默认的OAuth2客户端认证过滤器
    http.removeFilter(OAuth2ClientAuthenticationProcessingFilter.class);
    
    http.authorizeRequests()
            .antMatchers("/", "/login**", "/callback/**", "/resources/**", "/static/**", "/webjars/**", "/webjar/**", "/error**")
            .permitAll()
            .and()
            .authorizeRequests()
            .anyRequest()
            .authenticated()
            .and()
            .csrf().disable()
            .logout()
            .permitAll()
            .logoutSuccessUrl("/")
            .and().addFilterAt(createCustomOAuth2ClientAuthenticationProcessingFilter(), AbstractPreAuthenticatedProcessingFilter.class);
}

方案2:使用BeanPostProcessor替换默认过滤器实例

你提到的后置处理器方案适配性更强,不需要修改原有HttpSecurity配置,完全复用Spring Boot的自动配置逻辑,直接将默认过滤器实例替换为你自定义的实例即可,代码示例:

@Component
public class CustomFilterPostProcessor implements BeanPostProcessor {
    @Autowired
    private OAuth2SsoProperties sso;
    @Autowired
    private UserInfoRestTemplateFactory restTemplateFactory;
    @Autowired
    private ResourceServerTokenServices tokenServices;
    @Autowired
    private ApplicationEventPublisher eventPublisher;

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (bean instanceof OAuth2ClientAuthenticationProcessingFilter && !(bean instanceof CustomOAuth2ClientAuthenticationProcessingFilter)) {
            // 替换默认过滤器为自定义实例
            CustomOAuth2ClientAuthenticationProcessingFilter customFilter = new CustomOAuth2ClientAuthenticationProcessingFilter(sso.getLoginPath());
            customFilter.setRestTemplate(restTemplateFactory.getUserInfoRestTemplate());
            customFilter.setTokenServices(tokenServices);
            customFilter.setApplicationEventPublisher(eventPublisher);
            return customFilter;
        }
        return bean;
    }
}

方案3:轻量方案-自定义TokenServices调整权限(推荐)

你的核心需求是调整用户角色,不需要重写整个过滤器,直接自定义Token服务就能实现,更轻量不易出错:

@Service
public class CustomResourceServerTokenServices implements ResourceServerTokenServices {
    @Autowired
    private ResourceServerTokenServices defaultTokenServices;

    @Override
    public OAuth2Authentication loadAuthentication(String accessToken) throws AuthenticationException, InvalidTokenException {
        OAuth2Authentication originalAuth = defaultTokenServices.loadAuthentication(accessToken);
        // 调整权限,比如添加自定义角色
        List<GrantedAuthority> updatedAuthorities = new ArrayList<>(originalAuth.getAuthorities());
        updatedAuthorities.add(new SimpleGrantedAuthority("ROLE_CUSTOM_USER"));
        // 创建新的Authentication对象
        UsernamePasswordAuthenticationToken newUserAuth = new UsernamePasswordAuthenticationToken(originalAuth.getPrincipal(), originalAuth.getCredentials(), updatedAuthorities);
        newUserAuth.setDetails(originalAuth.getDetails());
        return new OAuth2Authentication(originalAuth.getOAuth2Request(), newUserAuth);
    }

    @Override
    public OAuth2AccessToken readAccessToken(String accessToken) {
        return defaultTokenServices.readAccessToken(accessToken);
    }
}

保留@Secured能力的注意事项

  • 确保你的配置类上添加了@EnableGlobalMethodSecurity(securedEnabled = true)开启方法级安全注解
  • 你自定义的角色权限默认需要带上ROLE_前缀,比如ROLE_ADMIN对应@Secured("ROLE_ADMIN"),如果要自定义前缀可以调整GrantedAuthorityDefaults配置
  • 上述三种方案都会将调整后的Authentication正确存入安全上下文,不会影响@Secured的校验逻辑

内容的提问来源于stack exchange,提问作者Georgi D.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 15:09:01