Spring OAuth:用于验证授权端点的自定义表单

Posted

技术标签:

【中文标题】Spring OAuth:用于验证授权端点的自定义表单【英文标题】:Spring OAuth: Custom form for authenticating authorization endpoint 【发布时间】:2015-10-15 06:31:07 【问题描述】:

如何在既是授权服务器又是资源服务器的 Spring Boot 应用程序中设置自定义登录表单以保护我的 /oauth/authorize 端点?我想实现用户必须登录才能向 /oauth/authorize 发出请求。所有不是 /login 和 /oauth/** 的资源都应作为受 OAuth 保护的安全资源进行处理(需要有效的访问令牌)

因此,当用户调用 localhost:1234/oauth/authorize?client_id=client&response_type=token&redirect_uri=http://localhost:5678 他首先被重定向到登录表单并在成功登录后重定向到 /oauth/authorize 端点,其中隐式 OAuth流程继续进行。

当我尝试以下操作时,它可以使用标准的基本身份验证弹出窗口

@Configuration
@EnableAuthorizationServer
public class OAuthConfig extends AuthorizationServerConfigurerAdapter 

    @Autowired
    private AuthenticationManager authenticationManager;

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception 
        endpoints.authenticationManager(authenticationManager);
    

    @Override
    public void configure(final ClientDetailsServiceConfigurer clients)
            throws Exception 
        clients.inMemory()
                .withClient("client")
                .authorizedGrantTypes("implicit", "refresh_token")
                .scopes("read");
    


资源配置

@Configuration
@EnableResourceServer
public class ResourceConfiguration
        extends ResourceServerConfigurerAdapter


    @Override
    public void configure(final HttpSecurity http) throws Exception 
        // @formatter:off
        http.authorizeRequests().antMatchers("/login").permitAll().and()
                .authorizeRequests().anyRequest().authenticated();
        // @formatter:on
    

网络安全配置

@Configuration
public class WebSecurityConfiguration
        extends WebSecurityConfigurerAdapter


    @Override
    protected void configure(HttpSecurity http) throws Exception 
        http.authorizeRequests().antMatchers("/oauth/authorize").authenticated().and()
                .authorizeRequests().anyRequest().permitAll().and().httpBasic();
    


但只要我用以下内容替换 httpBasic() 就会失败:

@Configuration
public class WebSecurityConfiguration
        extends WebSecurityConfigurerAdapter


    @Override
    protected void configure(HttpSecurity http) throws Exception 
         http.authorizeRequests().antMatchers("/oauth/authorize").authenticated().and()
         .authorizeRequests().anyRequest().permitAll().and().formLogin().loginPage("/login").and().csrf()
         .disable();
    


我的登录页面的 POST 没有被重定向,它总是返回到 /login

控制台输出如下

o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/login'; against '/css/**'
o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/login'; against '/js/**'
o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/login'; against '/images/**'
o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/login'; against '/**/favicon.ico'
o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/login'; against '/error'
o.s.s.web.util.matcher.OrRequestMatcher  : Trying to match using Ant [pattern='/oauth/token']
o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/login'; against '/oauth/token'
o.s.s.web.util.matcher.OrRequestMatcher  : Trying to match using Ant [pattern='/oauth/token_key']
o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/login'; against '/oauth/token_key'
o.s.s.web.util.matcher.OrRequestMatcher  : Trying to match using Ant [pattern='/oauth/check_token']
o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/login'; against '/oauth/check_token'
o.s.s.web.util.matcher.OrRequestMatcher  : No matches found
o.s.s.web.util.matcher.OrRequestMatcher  : Trying to match using org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfiguration$NotOAuthRequestMatcher@5fe3eb5f
o.s.s.web.util.matcher.OrRequestMatcher  : matched
o.s.security.web.FilterChainProxy        : /login at position 1 of 11 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
o.s.security.web.FilterChainProxy        : /login at position 2 of 11 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
o.s.security.web.FilterChainProxy        : /login at position 3 of 11 in additional filter chain; firing Filter: 'HeaderWriterFilter'
o.s.s.w.header.writers.HstsHeaderWriter  : Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@51c78264
o.s.security.web.FilterChainProxy        : /login at position 4 of 11 in additional filter chain; firing Filter: 'LogoutFilter'
o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/login'; against '/logout'
o.s.security.web.FilterChainProxy        : /login at position 5 of 11 in additional filter chain; firing Filter: 'OAuth2AuthenticationProcessingFilter'
o.s.s.o.p.a.BearerTokenExtractor         : Token not found in headers. Trying request parameters.
o.s.s.o.p.a.BearerTokenExtractor         : Token not found in request parameters.  Not an OAuth2 request.
p.a.OAuth2AuthenticationProcessingFilter : No token in request, will continue chain.
o.s.security.web.FilterChainProxy        : /login at position 6 of 11 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
o.s.security.web.FilterChainProxy        : /login at position 7 of 11 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
o.s.security.web.FilterChainProxy        : /login at position 8 of 11 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
o.s.s.w.a.AnonymousAuthenticationFilter  : Populated SecurityContextHolder with anonymous token: 'org.springframework.security.authentication.AnonymousAuthenticationToken@90541710: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@166c8: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: BDCE2D7EA7252AEA2506633726B8BA19; Granted Authorities: ROLE_ANONYMOUS'
o.s.security.web.FilterChainProxy        : /login at position 9 of 11 in additional filter chain; firing Filter: 'SessionManagementFilter'
o.s.security.web.FilterChainProxy        : /login at position 10 of 11 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
o.s.security.web.FilterChainProxy        : /login at position 11 of 11 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/login'; against '/login'
o.s.s.w.a.i.FilterSecurityInterceptor    : Secure object: FilterInvocation: URL: /login; Attributes: [#oauth2.throwOnError(permitAll)]
o.s.s.w.a.i.FilterSecurityInterceptor    : Previously Authenticated: org.springframework.security.authentication.AnonymousAuthenticationToken@90541710: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@166c8: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: BDCE2D7EA7252AEA2506633726B8BA19; Granted Authorities: ROLE_ANONYMOUS
o.s.s.access.vote.AffirmativeBased       : Voter: org.springframework.security.web.access.expression.WebExpressionVoter@bba9bfc, returned: 1
o.s.s.w.a.i.FilterSecurityInterceptor    : Authorization successful
o.s.s.w.a.i.FilterSecurityInterceptor    : RunAsManager did not change Authentication object
o.s.security.web.FilterChainProxy        : /login reached end of additional filter chain; proceeding with original chain
o.s.s.w.a.ExceptionTranslationFilter     : Chain processed normally
s.s.w.c.SecurityContextPersistenceFilter : SecurityContextHolder now cleared, as request processing completed

【问题讨论】:

【参考方案1】:

将@Order(-10) 添加到 WebSecurityConfig 可解决此问题。我认为这个注释可确保在 ResourceConfig 之前使用 WebSecurityConfig。我的最终配置如下所示:

@Configuration
@Order(-10)
public class WebSecurityConfig
        extends WebSecurityConfigurerAdapter


    @Autowired
    private AuthenticationManager authenticationManager;

    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception 
        auth.parentAuthenticationManager(authenticationManager);

    

    @Override
    protected void configure(HttpSecurity http) throws Exception 
        // @formatter:off
        http.authorizeRequests().antMatchers("/oauth/authorize").authenticated()
                .and()
                .authorizeRequests().anyRequest().permitAll()
                .and()
                .formLogin().loginPage("/login").permitAll()
                .and()
                .csrf().disable();
        // @formatter:on
    


【讨论】:

以上是关于Spring OAuth:用于验证授权端点的自定义表单的主要内容,如果未能解决你的问题,请参考以下文章

Spring 授权服务器核心协议端点

Spring oauth2服务器,无法验证令牌

具有多个grant_type的Spring Oauth2授权服务器用户信息端点不起作用

Spring Boot Security - 如果用户未通过 Oauth2 进行身份验证,如何禁用对 swagger ui 页面的端点的访问

Spring Security Oauth2

在 Spring 安全性中使用 rest 服务进行身份验证和授权 [关闭]