Java Spring OAuth2安全-客户端凭据-自定义身份验证提供程序

Java Spring OAuth2安全-客户端凭据-自定义身份验证提供程序,java,spring,authentication,spring-security,spring-security-oauth2,Java,Spring,Authentication,Spring Security,Spring Security Oauth2,我正在我们的服务体系结构中编写一个身份验证服务,它基本上是SpringOAuth2授权服务器的一个实现。因此,我需要针对许多不同的源对提供的凭据进行身份验证,以支持遗留环境 我主要集中于使用客户端凭据流,其中用户(其他服务)将使用自己的凭据来获取令牌,并且暂时不需要OAuth2的授权或刷新 我已经成功地启动了一个受Spring安全保护的Spring启动应用程序(@EnableWebSecurity)。我还成功地设置了授权服务器(@EnableAuthorizationServer),它提供了必要

我正在我们的服务体系结构中编写一个身份验证服务,它基本上是SpringOAuth2授权服务器的一个实现。因此,我需要针对许多不同的源对提供的凭据进行身份验证,以支持遗留环境

我主要集中于使用客户端凭据流,其中用户(其他服务)将使用自己的凭据来获取令牌,并且暂时不需要OAuth2的授权或刷新

我已经成功地启动了一个受Spring安全保护的Spring启动应用程序(
@EnableWebSecurity
)。我还成功地设置了授权服务器(
@EnableAuthorizationServer
),它提供了必要的端点(
/oauth/token
)来提供令牌。我已经能够使用内存和自定义ClientDetailsService配置授权服务器,以成功获取令牌。这一切都只是为了向自己证明,我可以让某些东西发挥作用

我的问题是,我需要根据自定义源对凭据进行身份验证。我无法直接访问密码,当然也不知道密码是如何编码的

在深入研究Spring代码之后,我可以看到通过
DaoAuthenticationProvider
,它通过调用
PasswordEncoder.matches()
来完成身份验证。不幸的是,我没有从
ClientDetailsService
获取密码,如果我获取了密码,我也不知道密码是如何编码的,因此自定义
PasswordEncoder
对我没有多大好处(我还需要以多种方式与一个
PasswordEncoder
匹配)。因此,我只剩下定义自己的
AuthenticationProvider
(或
AuthenticationManager

我能够实现自己的
AuthenticationProvider
,并将其提供给Spring安全配置。这非常有效,我能够将身份验证推迟到我自己的提供者,该提供者可以做我认为合适的任何事情(例如委托给另一个服务进行身份验证),但这只适用于非OAuth2端点

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    public AuthenticationProvider customAuthenticationProvider;

    @Bean(name = BeanIds.AUTHENTICATION_MANAGER)
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
//      return new ProviderManager(Arrays.asList(customAuthenticationProvider));
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
            .anyRequest()
            .authenticated()
        .and()
            .httpBasic();
    }

    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth
                .authenticationProvider(customAuthenticationProvider);
    }

//   @Autowired
//   public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
//       auth.authenticationProvider(customAuthenticationProvider);
//   }
}
现在一切都开始崩溃了。无论出于何种原因,我无法使
/oauth/token
端点使用我提供的已定义的
AuthenticationManager
AuthenticationProvider
s。它总是默认为
authenticationmanager
,带有
AnonymousAuthenticationProvider
DaoAuthenticationProvider

网站安全性

这里没什么意思。我正在全局公开身份验证管理器,以尝试在OAuth2配置中注册它。我留下了一些注释代码来展示我尝试过的其他一些东西,但它们几乎都完成了相同的事情:它可以处理除OAuth2端点之外的所有东西

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    public AuthenticationProvider customAuthenticationProvider;

    @Bean(name = BeanIds.AUTHENTICATION_MANAGER)
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
//      return new ProviderManager(Arrays.asList(customAuthenticationProvider));
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
            .anyRequest()
            .authenticated()
        .and()
            .httpBasic();
    }

    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth
                .authenticationProvider(customAuthenticationProvider);
    }

//   @Autowired
//   public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
//       auth.authenticationProvider(customAuthenticationProvider);
//   }
}
AuthServer

我已经把它简化为我认为应该是正确的配置。我特意省略了
ClientDetailsService
,因为它是提供者配置的一部分,并且工作正常。我将忽略
TokenStore
,并使用默认值,直到我可以获得身份验证为止。同样,这里的
authenticationManager
应该是从WebSecurity公开的全局管理器。我还尝试在endpoints configurer中创建一个新的
ProviderManager
,但这对我也不起作用

@Configuration
@EnableAuthorizationServer
public class AuthServerConfig extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private AuthenticationManager authenticationManager;

    @Override
    public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {        
        oauthServer
            .tokenKeyAccess("permitAll()")
            .checkTokenAccess("permitAll()")
        ;
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.authenticationManager(authenticationManager);
    }
}
我还尝试扩展了
AuthorizationServerSecurityConfiguration
,但没有成功:

@Configuration
@EnableAuthorizationServer
public class AuthServerConfig2 extends AuthorizationServerSecurityConfiguration {

    @Autowired
    public AuthenticationProvider customAuthenticationProvider;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(customAuthenticationProvider);
    }
}
我希望我的自定义
AuthenticationProvider
会显示在列表中,但它不会显示我尝试过的所有内容

这可能是有意的,但如果是这样,那么提供自定义身份验证方案的正确方法是什么


我真的很想避免它,但我真的需要实现一个自定义过滤器并绕过Spring提供的所有好东西吗?如果是,我该怎么做呢?

我最后配置了一个附加的
基本身份验证过滤器
到令牌端点。对我来说,这有点混乱,因为现在在安全过滤器链中有两个相同的过滤器,但它确实做到了

@Configuration
@EnableAuthorizationServer
public class AuthServerConfig extends AuthorizationServerConfigurerAdapter {
    @Autowired
    private UserService userService;

    @Autowired
    private AuthenticationManager authenticationManager;

    @Override
    public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
        oauthServer
            .tokenKeyAccess("isAuthenticated()")
            .checkTokenAccess("isAuthenticated()");

        // override the default basic authentication filter in order to provide
        // a custom authentication manager
        oauthServer.addTokenEndpointAuthenticationFilter(new BasicAuthenticationFilter(authenticationManager, new BasicAuthenticationEntryPoint()));
    }
}