spring安全permitAll仍然考虑在授权标头中传递的令牌,如果令牌无效则返回401

问题描述 投票:0回答:5

我在我的项目中使用 spring security oauth。我通过在 spring security ResourceServerConfigurerAdapter 中配置来从身份验证中排除一些 url。我添加了

http.authorizeRequests().antMatchers(url).permitAll()

现在,我看到的是,如果我不将 Authorization 标头传递给这些 url,则它不会经过身份验证。并且API被正确调用。

如果使用授权标头进行调用,则它将验证令牌,如果令牌未经过验证,则调用将失败。

我的问题是我需要做什么才能在我拥有 PermitAll 的请求中忽略令牌。

spring authentication spring-security spring-security-oauth2
5个回答
8
投票

Spring OAuth2 将拦截所有带有标题的 url:Authorization Bearer xxx。

避免 Spring OAuth2 拦截 url。我创建了一个 SecurityConfiguration,它的顺序比 Spring OAuth2 配置更高。

@Configuration
@EnableWebSecurity
@Order(1) // this is important to run this before Spring OAuth2 
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Override
    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        List<RequestMatcher> requestMatchers = new ArrayList<RequestMatcher>();
        // allow /api/public/product/** and /api/public/content/** not intercepted by Spring OAuth2
        requestMatchers.add(new AntPathRequestMatcher("/api/public/product/**"));
        requestMatchers.add(new AntPathRequestMatcher("/api/public/content/**"));

    http
        .requestMatcher(new OrRequestMatcher(requestMatchers))
    .authorizeRequests()
      .antMatchers("/api/public/product/**", "/api/public/content/**").permitAll()
    }
}

上述配置允许 /api/public/product/** 和 /api/public/content/** 由该配置处理,而不是由 Spring OAuth2 处理,因为该配置具有更高的 @Order。

因此,即使为上述 API 调用设置无效令牌也不会导致访问令牌无效。


4
投票

根据 spring-oauth2 文档 https://projects.spring.io/spring-security-oauth/docs/oauth2.html

注意:如果您的授权服务器也是资源服务器,那么还有另一个优先级较低的安全过滤器链控制 API 资源。对于那些受访问令牌保护的请求,您需要它们的路径不与面向用户的主过滤器链中的路径匹配,因此请务必包含一个请求匹配器,该匹配器仅在上面的 WebSecurityConfigurer 中挑选出非 API 资源。

因此定义比 ResourceServerConfig 更高阶的 WebSecurityConfigurer 实现。


0
投票

如果您正在处理 Reactive Spring webflux,请参见 SooCheng Koh 的回答。

@Configuration
@EnableWebFluxSecurity
@EnableReactiveMethodSecurity
@Order(1) // this is important to run this before Spring OAuth2
public class PublicSecurityConfiguration {


    @Bean
    public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {

        http

            .authorizeExchange()
            .pathMatchers("/api/public/**").permitAll();
        return http.build();
    }
}

0
投票

这不是一个错误,而是一个功能:)

正如其他人已经提到的,即使你有

permitAll
,Spring Security 仍然会检查令牌是否有标题“Authorization”。 我不喜欢后端使用
Order(1)
的解决方法,因此我对前端进行了更改,只需删除特定请求的标头“授权”即可。 带拦截器的 Angular 示例:

@Injectable()
export class PermitAllInterceptor implements HttpInterceptor {
  constructor() {}
  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    if(req.url.includes('permitAllUrl')){
      req = req.clone({ headers: req.headers.delete('Authorization') });
    }
    return next.handle(req);
  }
}

然后只需在 app.module.ts 中注册拦截器即可:

{
  provide: HTTP_INTERCEPTORS,
  useClass: PermitAllInterceptor ,
  multi: true
}

0
投票

对于 Spring Security 5、6,以下内容与 OAuth2ResourceServer 配合良好

@Configuration
@Order(1)
public class CustomSecurityConfiguration {

    @Bean
    public WebSecurityCustomizer webSecurityCustomizer() {
        return (web) -> web.ignoring()
                .requestMatchers(new AntPathRequestMatcher("/ignore1/**"))
                .requestMatchers(new AntPathRequestMatcher("/ignore2/**"));
}

}

© www.soinside.com 2019 - 2024. All rights reserved.