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.
相关产品推荐
相关产品推荐

