2016-07-31 69 views
5

我試圖用最新版本的Spring Boot,Web和安全實現自定義身份驗證邏輯,但我正在努力解決一些問題。我在類似的問題/教程中嘗試了很多解決方案,但沒有成功或理解實際發生的事情。Spring自定義身份驗證過濾器和提供程序不調用控制器方法

我使用無狀態身份驗證創建了一個REST應用程序,即有一個REST端點(/ web/auth/login)需要用戶名和密碼並返回一個字符串標記,然後在所有其他REST端點(/ api/**)來標識用戶。我需要實現一個定製的解決方案,因爲將來認證將變得更加複雜,我想了解Spring Security的基礎知識。

爲了實現令牌認證,我創建一個定製的過濾器,並提供:

過濾器:

public class TokenAuthenticationFilter extends AbstractAuthenticationProcessingFilter { 

public TokenAuthenticationFilter() { 
    super(new AntPathRequestMatcher("/api/**", "GET")); 
} 

@Override 
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException { 
    String token = request.getParameter("token"); 
    if (token == null || token.length() == 0) { 
     throw new BadCredentialsException("Missing token"); 
    } 

    UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(token, null); 

    return getAuthenticationManager().authenticate(authenticationToken); 
} 
} 

提供者:

@Component 
public class TokenAuthenticationProvider implements AuthenticationProvider { 
@Autowired 
private AuthenticationTokenManager tokenManager; 

@Override 
public Authentication authenticate(Authentication authentication) throws AuthenticationException { 
    String token = (String)authentication.getPrincipal(); 
    return tokenManager.getAuthenticationByToken(token); 
} 

@Override 
public boolean supports(Class<?> authentication) { 
    return UsernamePasswordAuthenticationToken.class.equals(authentication); 
} 
} 

的配置:

@EnableWebSecurity 
@Order(1) 
public class TokenAuthenticationSecurityConfig extends WebSecurityConfigurerAdapter { 
@Autowired 
private TokenAuthenticationProvider authProvider; 

@Override 
protected void configure(HttpSecurity http) throws Exception { 
    http.antMatcher("/api/**") 
    .csrf().disable() 
    .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) 
    .and().addFilterBefore(authenticationFilter(), BasicAuthenticationFilter.class); 
} 

@Bean 
public TokenAuthenticationFilter authenticationFilter() throws Exception { 
    TokenAuthenticationFilter tokenProcessingFilter = new TokenAuthenticationFilter(); 
    tokenProcessingFilter.setAuthenticationManager(authenticationManager()); 
    return tokenProcessingFilter; 
} 

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

AuthenticationTokenManager應用於供應商(以及在登錄過程):

@Component 
public class AuthenticationTokenManager { 
private Map<String, AuthenticationToken> tokens; 

public AuthenticationTokenManager() { 
    tokens = new HashMap<>(); 
} 

private String generateToken(AuthenticationToken authentication) { 
    return UUID.randomUUID().toString(); 
} 

public String addAuthentication(AuthenticationToken authentication) { 
    String token = generateToken(authentication); 
    tokens.put(token, authentication); 
    return token; 
} 

public AuthenticationToken getAuthenticationByToken(String token) { 
    return tokens.get(token); 
} 

}

會發生什麼: 我在請求中追加一個有效的標記爲「/ API/BLA 「(這是一個REST控制器返回一些Json)。過濾器和提供者都被調用。 問題是,瀏覽器被重定向到「/」而不是調用REST控制器的請求方法。這似乎發生在SavedRequestAwareAuthenticationSuccessHandler中,但爲什麼使用此處理程序?

我試圖

  • 實現空成功處理程序,導致200個狀態碼,但仍不能調用控制器
  • 做認證在一個簡單的GenericFilterBean並通過SecurityContextHolder中設置的認證對象.getContext()。setAuthentication(身份驗證)會導致「憑據錯誤」錯誤頁面。

我想了解爲什麼我的控制器不會在我驗證令牌後被調用。除此之外,是否存在一種「Spring」方式來存儲令牌,而不是將其存儲在Map中,就像SecurityContextRepository的自定義實現一樣?

我真的很感激任何提示!

+1

任何工作解決方案?我們有同樣的問題,任何提示或工作代碼都會很好。 – tg44

回答

0

可能有點晚,但我有同樣的問題,並補充說:

@Override 
protected void successfulAuthentication(
     final HttpServletRequest request, final HttpServletResponse response, 
     final FilterChain chain, final Authentication authResult) 
     throws IOException, ServletException { 
    chain.doFilter(request, response); 
} 

我AbstractAuthenticationProcessingFilter實施並獲得成功。

相關問題