2016-09-25 43 views
0

我有一個彈簧啓動+角度web應用程序,它嚴格遵循此tutorial的設置:我在同一個Spring Boot應用程序中運行授權服務器,資源服務器,UI Web應用程序。無法獲得Spring OAuth SSO過濾器來觸發

然後我有需要允許用戶登錄與第三方社會登錄(Facebook等),並隱式創建用戶帳戶,如果使用尚未註冊以前。

我試圖通過遵循另一個教程here來完成此操作。

在本教程中,使GET /login/facebook調用會觸發代碼中設置的SSOFilter。但是這並沒有發生在我自己的代碼中。我試圖將SSO過濾器的順序更改爲不同的數字,但它也沒有幫助。

在教程auth-server示例的日誌中。我看到下面的輸出:

2016-09-24 22:59:26.728 DEBUG 59433 --- [nio-8080-exec-1] o.s.s.w.u.matcher.AntPathRequestMatcher : Request '/login/facebook' matched by universal pattern '/**' 
2016-09-24 22:59:26.728 DEBUG 59433 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy  : /login/facebook at position 1 of 12 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter' 
2016-09-24 22:59:26.729 DEBUG 59433 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy  : /login/facebook at position 2 of 12 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter' 
2016-09-24 22:59:26.729 DEBUG 59433 --- [nio-8080-exec-1] w.c.HttpSessionSecurityContextRepository : No HttpSession currently exists 
2016-09-24 22:59:26.729 DEBUG 59433 --- [nio-8080-exec-1] w.c.HttpSessionSecurityContextRepository : No SecurityContext was available from the HttpSession: null. A new one will be created. 
2016-09-24 22:59:26.731 DEBUG 59433 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy  : /login/facebook at position 3 of 12 in additional filter chain; firing Filter: 'HeaderWriterFilter' 
2016-09-24 22:59:26.732 DEBUG 59433 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy  : /login/facebook at position 4 of 12 in additional filter chain; firing Filter: 'CsrfFilter' 
2016-09-24 22:59:26.736 DEBUG 59433 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy  : /login/facebook at position 5 of 12 in additional filter chain; firing Filter: 'LogoutFilter' 
2016-09-24 22:59:26.736 DEBUG 59433 --- [nio-8080-exec-1] o.s.s.w.u.matcher.AntPathRequestMatcher : Request 'GET /login/facebook' doesn't match 'POST /logout 
2016-09-24 22:59:26.736 DEBUG 59433 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy  : /login/facebook at position 6 of 12 in additional filter chain; firing Filter: 'CompositeFilter' 
2016-09-24 22:59:26.737 DEBUG 59433 --- [nio-8080-exec-1] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/login/facebook'; against '/login/facebook' 

在我自己的日誌中,我沒有看到過CompositeFilter被觸發:

2016-09-24 23:38:54.545 DEBUG 60184 --- [nio-8080-exec-1] o.s.s.w.u.matcher.AntPathRequestMatcher : Request '/login/facebook' matched by universal pattern '/**' 
2016-09-24 23:38:54.546 DEBUG 60184 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy  : /login/facebook at position 1 of 11 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter' 
2016-09-24 23:38:54.547 DEBUG 60184 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy  : /login/facebook at position 2 of 11 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter' 
2016-09-24 23:38:54.547 DEBUG 60184 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy  : /login/facebook at position 3 of 11 in additional filter chain; firing Filter: 'HeaderWriterFilter' 
2016-09-24 23:38:54.548 DEBUG 60184 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy  : /login/facebook at position 4 of 11 in additional filter chain; firing Filter: 'LogoutFilter' 
2016-09-24 23:38:54.548 DEBUG 60184 --- [nio-8080-exec-1] o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using Ant [pattern='/logout', GET] 
2016-09-24 23:38:54.548 DEBUG 60184 --- [nio-8080-exec-1] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/login/facebook'; against '/logout' 
2016-09-24 23:38:54.548 DEBUG 60184 --- [nio-8080-exec-1] o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using Ant [pattern='/logout', POST] 
2016-09-24 23:38:54.548 DEBUG 60184 --- [nio-8080-exec-1] o.s.s.w.u.matcher.AntPathRequestMatcher : Request 'GET /login/facebook' doesn't match 'POST /logout 
2016-09-24 23:38:54.548 DEBUG 60184 --- [nio-8080-exec-1] o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using Ant [pattern='/logout', PUT] 
2016-09-24 23:38:54.548 DEBUG 60184 --- [nio-8080-exec-1] o.s.s.w.u.matcher.AntPathRequestMatcher : Request 'GET /login/facebook' doesn't match 'PUT /logout 
2016-09-24 23:38:54.548 DEBUG 60184 --- [nio-8080-exec-1] o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using Ant [pattern='/logout', DELETE] 
2016-09-24 23:38:54.549 DEBUG 60184 --- [nio-8080-exec-1] o.s.s.w.u.matcher.AntPathRequestMatcher : Request 'GET /login/facebook' doesn't match 'DELETE /logout 
2016-09-24 23:38:54.549 DEBUG 60184 --- [nio-8080-exec-1] o.s.s.web.util.matcher.OrRequestMatcher : No matches found 
2016-09-24 23:38:54.549 DEBUG 60184 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy  : /login/facebook at position 5 of 11 in additional filter chain; firing Filter: 'OAuth2AuthenticationProcessingFilter' 
2016-09-24 23:38:54.549 DEBUG 60184 --- [nio-8080-exec-1] o.s.s.o.p.a.BearerTokenExtractor   : Token not found in headers. Trying request parameters. 
2016-09-24 23:38:54.549 DEBUG 60184 --- [nio-8080-exec-1] o.s.s.o.p.a.BearerTokenExtractor   : Token not found in request parameters. Not an OAuth2 request. 
2016-09-24 23:38:54.549 DEBUG 60184 --- [nio-8080-exec-1] p.a.OAuth2AuthenticationProcessingFilter : No token in request, will continue chain. 
2016-09-24 23:38:54.549 DEBUG 60184 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy  : /login/facebook at position 6 of 11 in additional filter chain; firing Filter: 'RequestCacheAwareFilter' 
2016-09-24 23:38:54.549 DEBUG 60184 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy  : /login/facebook at position 7 of 11 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter' 
2016-09-24 23:38:54.550 DEBUG 60184 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy  : /login/facebook at position 8 of 11 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter' 
2016-09-24 23:38:54.551 DEBUG 60184 --- [nio-8080-exec-1] o.s.s.w.a.AnonymousAuthenticationFilter : Populated SecurityContextHolder with anonymous token: 'org.sprin[email protected]9055c2bc: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.sprin[email protected]b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: null; Granted Authorities: ROLE_ANONYMOUS' 
2016-09-24 23:38:54.551 DEBUG 60184 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy  : /login/facebook at position 9 of 11 in additional filter chain; firing Filter: 'SessionManagementFilter' 
2016-09-24 23:38:54.552 DEBUG 60184 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy  : /login/facebook at position 10 of 11 in additional filter chain; firing Filter: 'ExceptionTranslationFilter' 
2016-09-24 23:38:54.552 DEBUG 60184 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy  : /login/facebook at position 11 of 11 in additional filter chain; firing Filter: 'FilterSecurityInterceptor' 
2016-09-24 23:38:54.552 DEBUG 60184 --- [nio-8080-exec-1] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/login/facebook'; against '/api/**' 
2016-09-24 23:38:54.552 DEBUG 60184 --- [nio-8080-exec-1] o.s.s.w.a.i.FilterSecurityInterceptor : Public object - authentication not attempted 
2016-09-24 23:38:54.553 DEBUG 60184 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy  : /login/facebook reached end of additional filter chain; proceeding with original chain 
2016-09-24 23:38:54.571 DEBUG 60184 --- [nio-8080-exec-1] .s.o.p.e.FrameworkEndpointHandlerMapping : Looking up handler method for path /login/facebook 
2016-09-24 23:38:54.571 DEBUG 60184 --- [nio-8080-exec-1] .s.o.p.e.FrameworkEndpointHandlerMapping : Did not find handler method for [/login/facebook] 
2016-09-24 23:38:54.574 DEBUG 60184 --- [nio-8080-exec-1] o.s.s.w.header.writers.HstsHeaderWriter : Not injecting HSTS header since it did not match the requestMatcher org.springframework.se[email protected]76f064a2 

我拉我的頭髮掉,但仍毫無頭緒出了什麼錯我的代碼。

這是我設置的代碼片段:

主類文件:

@SpringBootApplication 
public class TuangouApplication extends SpringBootServletInitializer { 

    public static void main(String[] args) throws Exception { 
     SpringApplication.run(TuangouApplication.class, args); 
    } 

    // this is for WAR file deployment 
    @Override 
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { 
     return application.sources(TuangouApplication.class); 
    } 

    @Bean 
    public javax.validation.Validator localValidatorFactoryBean() { 
     return new LocalValidatorFactoryBean(); 
    } 
} 

WebSecurityConfiguration文件。 幾乎與spring oauth2教程auth-server示例相同。

@Configuration 
@EnableOAuth2Client 
@Order(6) 
public class TuangouConfiguration extends WebSecurityConfigurerAdapter { 

    @Autowired 
    private OAuth2ClientContext oauth2ClientContext; 

    @Override 
    protected void configure(HttpSecurity http) throws Exception { 
     // @formatter:off 
     http.antMatcher("/**").authorizeRequests().antMatchers("/", "/login**").permitAll() 
      .and().exceptionHandling().authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/")) 
      .and().formLogin().loginPage("/login").failureUrl("/login?error").permitAll() 
      .and().logout().logoutSuccessUrl("/").permitAll() 
      .and().csrf().csrfTokenRepository(csrfTokenRepository()) 
      .and().addFilterBefore(ssoFilter(), BasicAuthenticationFilter.class); 
     // @formatter:on 
    } 

// @Order(Ordered.HIGHEST_PRECEDENCE) 
    @Configuration 
    @EnableGlobalMethodSecurity(prePostEnabled=true) 
    protected static class AuthenticationSecurity extends GlobalAuthenticationConfigurerAdapter { 

     @Override 
     public void init(AuthenticationManagerBuilder auth) throws Exception { 
      auth.userDetailsService(userDetailsService()).passwordEncoder(new BCryptPasswordEncoder()); 
     } 

     @Bean 
     public UserDetailsService userDetailsService() { 
      return new DatabaseUserServiceDetails(); 
     } 
    } 

    private Filter csrfHeaderFilter() { 
     return new OncePerRequestFilter() { 
      @Override 
      protected void doFilterInternal(HttpServletRequest request, 
        HttpServletResponse response, FilterChain filterChain) 
          throws ServletException, IOException { 
       CsrfToken csrf = (CsrfToken) request 
         .getAttribute(CsrfToken.class.getName()); 
       if (csrf != null) { 
        Cookie cookie = WebUtils.getCookie(request, "XSRF-TOKEN"); 
        String token = csrf.getToken(); 
        if (cookie == null 
          || token != null && !token.equals(cookie.getValue())) { 
         cookie = new Cookie("XSRF-TOKEN", token); 
         cookie.setPath("/"); 
         response.addCookie(cookie); 
        } 
       } 
       filterChain.doFilter(request, response); 
      } 
     }; 
    } 

    private CsrfTokenRepository csrfTokenRepository() { 
     HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository(); 
     repository.setHeaderName("X-XSRF-TOKEN"); 
     return repository; 
    } 

    @Bean 
    public FilterRegistrationBean oauth2ClientFilterRegistration(OAuth2ClientContextFilter filter) { 
     FilterRegistrationBean registration = new FilterRegistrationBean(); 
     System.out.println("### foobar"); 
     registration.setFilter(filter); 
     registration.setOrder(-100); 
     return registration; 
    } 

    @Bean 
    @ConfigurationProperties("github") 
    public ClientResources github() { 
     return new ClientResources(); 
    } 

    @Bean 
    @ConfigurationProperties("facebook") 
    public ClientResources facebook() { 
     return new ClientResources(); 
    } 

    private Filter ssoFilter() { 
     CompositeFilter filter = new CompositeFilter(); 
     List<Filter> filters = new ArrayList<Filter>(); 
     filters.add(ssoFilter(facebook(), "/login/facebook")); 
     filters.add(ssoFilter(github(), "/login/github")); 
     filter.setFilters(filters); 
     return filter; 
    } 

    private Filter ssoFilter(ClientResources client, String path) { 
     OAuth2ClientAuthenticationProcessingFilter filter = new OAuth2ClientAuthenticationProcessingFilter(
       path); 
     OAuth2RestTemplate template = new OAuth2RestTemplate(client.getClient(), oauth2ClientContext); 
     filter.setRestTemplate(template); 
     filter.setTokenServices(new UserInfoTokenServices(
       client.getResource().getUserInfoUri(), client.getClient().getClientId())); 
     return filter; 
    } 
} 

class ClientResources { 

    @NestedConfigurationProperty 
    private AuthorizationCodeResourceDetails client = new AuthorizationCodeResourceDetails(); 

    @NestedConfigurationProperty 
    private ResourceServerProperties resource = new ResourceServerProperties(); 

    public AuthorizationCodeResourceDetails getClient() { 
     return client; 
    } 

    public ResourceServerProperties getResource() { 
     return resource; 
    } 
} 

授權服務器的配置:

@Configuration 
@EnableAuthorizationServer 
public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter { 

    @Autowired 
    private AuthenticationManager auth; 

    @Autowired 
    private DataSource dataSource; 

    private BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder(); 

    @Bean 
    public JdbcTokenStore tokenStore() { 
     return new JdbcTokenStore(dataSource); 
    } 

    @Bean 
    protected AuthorizationCodeServices authorizationCodeServices() { 
     return new JdbcAuthorizationCodeServices(dataSource); 
    } 

    @Override 
    public void configure(AuthorizationServerSecurityConfigurer security) 
      throws Exception { 
     security.passwordEncoder(passwordEncoder); 
    } 

    @Override 
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) 
      throws Exception { 
     endpoints.authorizationCodeServices(authorizationCodeServices()) 
       .authenticationManager(auth).tokenStore(tokenStore()) 
       .approvalStoreDisabled(); 
    } 

    @Override 
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception { 
     // @formatter:off 
     clients.jdbc(dataSource).passwordEncoder(passwordEncoder); 
//   .withClient("grubmarket") 
//    .authorizedGrantTypes("password", "authorization_code", "client_credentials", 
//      "refresh_token", "implicit") 
//    .authorities("ROLE_CLIENT", "ROLE_TRUSTED_CLIENT") 
//    .scopes("read", "write", "trust") 
//    .resourceIds("oauth2-resource") 
//    .accessTokenValiditySeconds(3600); 
     // @formatter:on 
    } 
} 

資源服務器配置:

@Configuration 
@EnableResourceServer 
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter{ 

    @Autowired 
    private TokenStore tokenStore; 

    @Override 
    public void configure(ResourceServerSecurityConfigurer resources) 
      throws Exception { 
     resources.tokenStore(tokenStore); 
    } 

    @Override 
    public void configure(HttpSecurity http) throws Exception { 
     // @formatter:off 
     http.antMatcher("/**").authorizeRequests().antMatchers("/api/**").permitAll(); 
//  http.antMatcher("/api/**").authorizeRequests().antMatchers(HttpMethod.GET, "/api/deals").permitAll().anyRequest().authenticated(); 
     // @formatter:on 
    } 
} 

回答

0

默認@Orderorg.springframework.security.oauth2.config.annotation.web.configuration.ResourcererverConfiguration是3

您的TuangouConfiguration設置爲@Order(6)。因此,如果您將其更改爲@Order(2),請求時將會調用ssoFilter或CompositeFilterGET /login/facebook

+0

工作正常!我在哪裏可以找到各種過濾器的默認訂單?當程序運行時,是否可以打印出或記錄所有過濾器的相對順序? –

+0

由'@ EnableResourceServer'創建的Spring安全篩選器鏈的默認順序在javadoc - ...硬編碼Order(of 3)中指定。另外,你可以通過在你的'TuangouConfiguration'中覆蓋以下內容來調試它們各自鏈中過濾器的順序....'public void configure(WebSecurity web)拋出異常{ \t \t web.debug(true); \t} ' –

+0

另一個需要注意的重要配置是'HttpSecurity.antMatcher()'。我注意到你在'TuangouConfiguration'和'ResourceServerConfiguration'中使用了它們,但它們都在'/ **'上匹配。我建議在'ResourceServerConfiguration'上使用更具體的模式,例如'/ api/**'。這也可以,並且當請求是'/ login/facebook'時,你可以調用你的'ssoFilter',並且不需要在你的'TuangouConfiguration'上使用@Order。我強烈建議使用這種配置方法。 –