2016-12-28 261 views
0

我使用Spring boot + data rest建立了一個純json rest服務,現在無法讓我的自定義身份驗證成功處理程序(以及身份驗證失敗處理程序)處理登錄響應。登錄本身就像它應該的那樣工作,但是服務器響應成功的登錄而沒有重定向url(這會在javascript的XMLHttpRequest中觸發一個錯誤)並且完全忽略在config中設置的處理程序。Spring Security自定義AuthenticationSuccessHandler被忽略

WebSecurityConfig:

@Configuration 
@EnableWebSecurity 
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, proxyTargetClass = true) 
public class WebSecurityConfig extends WebSecurityConfigurerAdapter { 

@Autowired 
private UserDetailsService userDetailsService; 

@Autowired 
private RESTAuthenticationEntryPoint authenticationEntryPoint; 
@Autowired 
private RESTAuthenticationFailureHandler authenticationFailureHandler; 
@Autowired 
private RESTAuthenticationSuccessHandler authenticationSuccessHandler; 
@Autowired 
private RESTLogoutSuccessHandler logoutSuccessHandler; 

@Bean 
public BCryptPasswordEncoder bCryptPasswordEncoder() { 
    return new BCryptPasswordEncoder(); 
} 

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

    http 
     .cors(); 

    http 
     .exceptionHandling() 
     .authenticationEntryPoint(authenticationEntryPoint); 

    http 
     .formLogin() 
     .permitAll() 
     .loginProcessingUrl("/login") 
     .successHandler(authenticationSuccessHandler) 
     .failureHandler(authenticationFailureHandler); 

    http 
     .logout() 
     .permitAll() 
     .logoutUrl("/logout") 
     .logoutSuccessHandler(logoutSuccessHandler); 

    http 
     .sessionManagement() 
     .maximumSessions(1); 

    http.addFilterAt(getAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class); 
    http.addFilterAfter(new CsrfTokenResponseHeaderBindingFilter(), CsrfFilter.class); 

    http.authorizeRequests().anyRequest().authenticated(); 
} 

@Bean 
public CorsConfigurationSource corsConfigurationSource() { 
    CorsConfiguration configuration = new CorsConfiguration(); 
    configuration.addAllowedOrigin("*"); 
    configuration.setAllowCredentials(true); 
    configuration.setExposedHeaders(Arrays.asList("X-CSRF-TOKEN")); 
     configuration.setAllowedHeaders(Arrays.asList("X-CSRF-TOKEN", "content-type")); 
    configuration.setAllowedMethods(Arrays.asList("GET","POST","OPTIONS")); 
    configuration.setMaxAge(3600L); 
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); 
    source.registerCorsConfiguration("/**", configuration); 
    return source; 
} 

@Bean 
public PermissionEvaluator customPermissionEvaluator() { 
    return new CustomPermissionEvaluator(); 
} 

protected CustomUsernamePasswordAuthenticationFilter getAuthenticationFilter() { 
    CustomUsernamePasswordAuthenticationFilter authFilter = new CustomUsernamePasswordAuthenticationFilter(); 
    try { 
     authFilter.setAuthenticationManager(this.authenticationManagerBean()); 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 
    return authFilter; 
} 

@Autowired 
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { 
    auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder()); 
} 
} 

AuthenticationSuccessHandler:

@Component 
public class RESTAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler { 

@Override 
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, 
            Authentication authentication) throws IOException, ServletException { 
    response.setStatus(HttpServletResponse.SC_OK); 
    PrintWriter writer = response.getWriter(); 
    writer.write("Login OK"); 
    writer.flush();   
    clearAuthenticationAttributes(request); 
} 
} 

CustomUsernamePasswordAuthenticationFilter剛從JSON讀取用戶名和密碼,它不會覆蓋所述過濾器()方法:

public class CustomUsernamePasswordAuthenticationFilter extends UsernamePasswordAuthenticationFilter { 

private final Logger log = LoggerFactory.getLogger(this.getClass()); 

private boolean postOnly = true; 

@Override 
public Authentication attemptAuthentication(HttpServletRequest request, 
     HttpServletResponse response) throws AuthenticationException { 

    if (postOnly && !request.getMethod().equals("POST")) { 
     throw new AuthenticationServiceException(
       "Authentication method not supported: " + request.getMethod()); 
    } 

    LoginRequest loginRequest; 
    try { 
     BufferedReader reader = request.getReader(); 
     StringBuffer sb = new StringBuffer(); 
     String line = null; 
     while ((line = reader.readLine()) != null){ 
      sb.append(line); 
     } 
     ObjectMapper mapper = new ObjectMapper(); 
     loginRequest = mapper.readValue(sb.toString(), LoginRequest.class); 
    } catch (Exception ex) { 
     throw new AuthenticationServiceException("Unable to read login credentials."); 
    } 

    UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(
      loginRequest.getEmail(), loginRequest.getPassword()); 

    setDetails(request, authRequest); 
    return this.getAuthenticationManager().authenticate(authRequest); 
} 
} 

在調試日誌我可以看到有一個奇怪的RequestAwar eAuthenticationSuccessHandler是獲取登錄處理後的請求,只是傳遞一個默認重定向到「/」:

2016-12-28 15:44:02.358 DEBUG 6194 --- [nio-8080-exec-7] o.s.s.authentication.ProviderManager  : Authentication attempt using org.springframework.security.authentication.dao.DaoAuthenticationProvider 
2016-12-28 15:44:02.358 DEBUG 6194 --- [nio-8080-exec-7] o.s.orm.jpa.JpaTransactionManager  : Creating new transaction with name [xxx.server.service.impl.UserDetailsServiceImpl.loadUserByUsername]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT,readOnly; '' 
2016-12-28 15:44:02.358 DEBUG 6194 --- [nio-8080-exec-7] o.s.orm.jpa.JpaTransactionManager  : Opened new EntityManager [[email protected]] for JPA transaction 
2016-12-28 15:44:02.358 DEBUG 6194 --- [nio-8080-exec-7] o.s.jdbc.datasource.DataSourceUtils  : Setting JDBC Connection [ProxyConnection[PooledConnection[[email protected]]]] read-only 
2016-12-28 15:44:02.358 DEBUG 6194 --- [nio-8080-exec-7] o.s.orm.jpa.JpaTransactionManager  : Exposing JPA transaction as JDBC transaction [org.springframewo[email protected]7cf6e5f] 
[...] 
2016-12-28 15:44:02.380 DEBUG 6194 --- [nio-8080-exec-7] o.s.orm.jpa.JpaTransactionManager  : Initiating transaction commit 
2016-12-28 15:44:02.380 DEBUG 6194 --- [nio-8080-exec-7] o.s.orm.jpa.JpaTransactionManager  : Committing JPA transaction on EntityManager [[email protected]] 
2016-12-28 15:44:02.381 DEBUG 6194 --- [nio-8080-exec-7] o.s.jdbc.datasource.DataSourceUtils  : Resetting read-only flag of JDBC Connection [ProxyConnection[PooledConnection[[email protected]]]] 
2016-12-28 15:44:02.381 DEBUG 6194 --- [nio-8080-exec-7] o.s.orm.jpa.JpaTransactionManager  : Closing JPA EntityManager [[email protected]] after transaction 
2016-12-28 15:44:02.381 DEBUG 6194 --- [nio-8080-exec-7] o.s.orm.jpa.EntityManagerFactoryUtils : Closing JPA EntityManager 
2016-12-28 15:44:02.488 DEBUG 6194 --- [nio-8080-exec-7] RequestAwareAuthenticationSuccessHandler : Using default Url:/
2016-12-28 15:44:02.488 DEBUG 6194 --- [nio-8080-exec-7] o.s.s.web.DefaultRedirectStrategy  : Redirecting to '/' 
2016-12-28 15:44:02.488 DEBUG 6194 --- [nio-8080-exec-7] o.s.s.w.header.writers.HstsHeaderWriter : Not injecting HSTS header since it did not match the requestMatcher org.springframework.se[email protected]273d8edd 
2016-12-28 15:44:02.488 DEBUG 6194 --- [nio-8080-exec-7] w.c.HttpSessionSecurityContextRepository : SecurityContext '[email protected]a222b9: Authentication: org.springframew[email protected]faa222b9: Principal: [email protected]: Username: [email protected]; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: USER; Credentials: [PROTECTED]; Authenticated: true; Details: org.sprin[email protected]fffed504: RemoteIpAddress: 127.0.0.1; SessionId: 1F3FF4A3203600AE56E3CB391BE96EFC; Granted Authorities: USER' stored to HttpSession: '[email protected] 
2016-12-28 15:44:02.488 DEBUG 6194 --- [nio-8080-exec-7] s.s.w.c.SecurityContextPersistenceFilter : SecurityContextHolder now cleared, as request processing completed 

回答

0
http 
     .formLogin() 
     .permitAll() 
     .loginProcessingUrl("/login") 
     .successHandler(authenticationSuccessHandler) 
     .failureHandler(authenticationFailureHandler); 

你自己authenticationSuccessHandler注入到UsernamePasswordAuthenticationFilter,並添加擴展UsernamePasswordAuthenticationFilter代替UsernamePasswordAuthenticationFilter

http.addFilterAt(getAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class); 
CustomUsernamePasswordAuthenticationFilter

但是您自己的CustomUsernamePasswordAuthenticationFilter使用默認成功處理程序。

protected CustomUsernamePasswordAuthenticationFilter getAuthenticationFilter() { 
    CustomUsernamePasswordAuthenticationFilter authFilter = new CustomUsernamePasswordAuthenticationFilter(); 
    try { 
     authFilter.setAuthenticationManager(this.authenticationManagerBean()); 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 
    return authFilter; 
} 

我看不到你注入您的成功處理程序CustomUsernamePasswordAuthenticationFilter任何代碼。

您需要將成功處理程序添加到CustomUsernamePasswordAuthenticationFilter

authFilter.setAuthenticationManager(this.authenticationManagerBean()); 
// set handler   
authFilter.setAuthenticationSuccessHandler(authenticationSuccessHandler);  
authFilter.setAuthenticationFailureHandler(authenticationFailureHandler); 
相關問題