对同一资源使用Oauth2或Http-Basic身份验证的Spring安全性

use*_*594 29 java security spring-security spring-security-oauth2

我正在尝试使用受Oauth2或Http-Basic身份验证保护的资源来实现API.

当我加载首先将http-basic身份验证应用于资源的WebSecurityConfigurerAdapter时,不接受Oauth2令牌身份验证.反之亦然.

示例配置: 这将http-basic身份验证应用于所有/ user/**资源

@Configuration
@EnableWebMvcSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    private LoginApi loginApi;

    @Autowired
    public void setLoginApi(LoginApi loginApi) {
        this.loginApi = loginApi;
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(new PortalUserAuthenticationProvider(loginApi));
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .antMatchers("/users/**").authenticated()
                .and()
            .httpBasic();
    }

    @Override
    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }
}
Run Code Online (Sandbox Code Playgroud)

这将oauth令牌保护应用于/ user/**资源

@Configuration
@EnableResourceServer
protected static class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http
            .requestMatchers().antMatchers("/users/**")
        .and()
            .authorizeRequests()
                .antMatchers("/users/**").access("#oauth2.clientHasRole('ROLE_CLIENT') and #oauth2.hasScope('read')");
    }
}
Run Code Online (Sandbox Code Playgroud)

我确定有一些我遗漏的魔法代码告诉spring如果第一次失败会尝试两者?

任何援助都将非常感激.

小智 35

我根据迈克尔雷斯勒的回答提示了这项工作,但进行了一些调整.

我的目标是在同一资源端点上允许Basic Auth和Oauth,例如/ leafcase/123.由于filterChains的排序,我被困了很长时间(可以在FilterChainProxy.filterChains中检查); 默认顺序如下:

  • Oauth身份验证服务器(如果在同一个项目中启用)的filterChains.默认顺序0(请参阅AuthorizationServerSecurityConfiguration)
  • Oauth资源服务器的filterChains.默认顺序3(请参阅ResourceServerConfiguration).它有一个请求匹配器逻辑,它匹配Oauth身份验证端点以外的任何东西(例如,/ oauth/token,/ oauth/authorize等.请参阅ResourceServerConfiguration $ NotOauthRequestMatcher.matches()).
  • 与config(HttpSecurity http)对应的filterChains - 默认顺序100,请参阅WebSecurityConfigurerAdapter.

由于资源服务器的filterChains排名高于WebSecurityConfigurerAdapter配置的filterchain,并且前者几乎匹配每个资源端点,因此Oauth资源服务器逻辑总是会对资源端点的任何请求启动(即使请求使用Authorization:Basic标头).你会得到的错误是:

{
    "error": "unauthorized",
    "error_description": "Full authentication is required to access this resource"
}
Run Code Online (Sandbox Code Playgroud)

我做了2个更改来完成这项工作:

首先,将WebSecurityConfigurerAdapter命令高于资源服务器(订单2高于订单3).

@Configuration
@Order(2)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
Run Code Online (Sandbox Code Playgroud)

其次,让configure(HttpSecurity)使用仅匹配"Authorization:Basic"的客户RequestMatcher.

@Override
protected void configure(HttpSecurity http) throws Exception {

    http
        .anonymous().disable()
        .requestMatcher(new BasicRequestMatcher())
        .authorizeRequests()
            .anyRequest().authenticated()
            .and()
        .httpBasic()
             .authenticationEntryPoint(oAuth2AuthenticationEntryPoint())
            .and()
        // ... other stuff
 }
 ...
 private static class BasicRequestMatcher implements RequestMatcher {
    @Override
    public boolean matches(HttpServletRequest request) {
        String auth = request.getHeader("Authorization");
        return (auth != null && auth.startsWith("Basic"));
    }
 }
Run Code Online (Sandbox Code Playgroud)

因此,在资源服务器的filterChain有机会匹配它之前,它匹配并处理Basic Auth资源请求.它还只处理Authorizaiton:基本资源请求,因此任何具有Authorization:Bearer的请求都将通过,然后由资源服务器的filterChain处理(即,Oauth的过滤器启动).此外,它的排名低于AuthenticationServer(如果在同一个项目上启用了AuthenticationServer),因此它不会阻止AuthenticaitonServer的过滤链处理对/ oauth/token等的请求.

  • `oAuth2AuthenticationEntryPoint()`在哪里定义? (7认同)
  • 任何人都知道如何正确地进行基于会话的身份验证?(表格登录) (2认同)

Mic*_*ler 5

这可能接近你想要的:

@Override
public void configure(HttpSecurity http) throws Exception {
    http.requestMatcher(new OAuthRequestedMatcher())
    .authorizeRequests()
        .anyRequest().authenticated();
}

private static class OAuthRequestedMatcher implements RequestMatcher {
    @Override
    public boolean matches(HttpServletRequest request) {
        String auth = request.getHeader("Authorization");
        // Determine if the client request contained an OAuth Authorization
        return (auth != null) && auth.startsWith("Bearer");
    }
}
Run Code Online (Sandbox Code Playgroud)

如果身份验证不成功,那么唯一没有提供的方法是"退回".

对我来说,这种方法是有道理的.如果用户通过基本身份验证直接向请求提供身份验证,则无需OAuth.如果客户端是代理客户端,那么我们需要此过滤器进入并确保请求已正确验证.


rao*_*sto 0

我认为不可能同时拥有这两种身份验证。您可以使用基本身份验证和 oauth2 身份验证,但针对不同的端点。正如您所做的那样,第一个配置将克服第二个配置,在这种情况下,将使用 http basic。