对同一资源使用 Oauth2 或 Http-Basic 身份验证的 Spring 安全性 [英] Spring security with Oauth2 or Http-Basic authentication for the same resource

查看:91
本文介绍了对同一资源使用 Oauth2 或 Http-Basic 身份验证的 Spring 安全性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm attempting to implement an API with resources that are protected by either Oauth2 OR Http-Basic authentication.

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

When I load the WebSecurityConfigurerAdapter which applies http-basic authentication to the resource first, Oauth2 token authentication is not accepted. And vice-versa.

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

Example configurations: This applies http-basic authentication to all /user/** resources

@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();
    }
}

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

This applies oauth token protection to the /user/** resource

@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')");
    }
}

我确定我遗漏了一些魔法代码,如果第一个失败,它会告诉 spring 尝试两者?

I'm sure there is some piece of magic code I'm missing which tells spring to attempt both if the first has failed?

任何帮助将不胜感激.

推荐答案

我根据 Michael Ressler 的回答的提示设法完成了这项工作,但做了一些调整.

I managed to get this work based on the hints by Michael Ressler's answer but with some tweaks.

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

My goal was to allow both Basic Auth and Oauth on the same resource endpoints, e.g., /leafcase/123. I was trapped for quite some time due to the ordering of the filterChains (can be inspected in FilterChainProxy.filterChains); the default order is as follows:

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

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

Since resource server's filterChains ranks higher than the one by WebSecurityConfigurerAdapter configured filterchain, and the former matches practically every resource endpoint, then Oauth resource server logic always kick in for any request to resource endpoints (even if the request uses the Authorization:Basic header). The error you would get is:

{
    "error": "unauthorized",
    "error_description": "Full authentication is required to access this resource"
}

我进行了 2 处更改以完成这项工作:

I made 2 changes to get this work:

首先将WebSecurityConfigurerAdapter排序高于资源服务器(2阶高于3阶).

Firstly, order the WebSecurityConfigurerAdapter higher than the resource server (order 2 is higher than order 3).

@Configuration
@Order(2)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

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

Secondly, let configure(HttpSecurity) use a customer RequestMatcher that only matches "Authorization: Basic".

@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"));
    }
 }

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

As a result it matches and handles a Basic Auth resource request before the resource server's filterChain has a chance to match it. It also ONLY handles Authorizaiton:Basic resource request, thus any requests with Authorization:Bearer will fall through, and then handled by resource server's filterChain (i.e., Oauth's filter kicks in). Also, it ranks lower than the AuthenticationServer (in case AuthenticationServer is enabled on the same project), so it doesn't prevent AuthenticaitonServer's filterchain from handling the request to /oauth/token, etc.

这篇关于对同一资源使用 Oauth2 或 Http-Basic 身份验证的 Spring 安全性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆