Spring自定义身份验证筛选器和提供程序不调用控制器方法

时间:2016-07-31 04:12:32

标签: java spring spring-mvc authentication spring-security

我尝试使用最新版本的Spring Boot,Web和安全性来实现自定义身份验证逻辑,但我正在努力解决一些问题。我在类似的问题/教程中尝试了许多解决方案而没有成功或理解实际发生的事情。

我正在使用无状态身份验证创建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);
}

}

会发生什么: 我将请求中的有效令牌附加到&#34; / api / bla&#34; (这是一个返回一些Json的REST控制器)。调用过滤器和提供程序。 问题是,浏览器被重定向到&#34; /&#34;而不是调用REST控制器的请求方法。这似乎发生在SavedRequestAwareAuthenticationSuccessHandler中,但为什么要使用这个处理程序?

我试过

  • 实现一个空的成功处理程序,导致200状态代码,但仍然没有调用控制器
  • 在简单的GenericFilterBean中进行身份验证,并通过SecurityContextHolder.getContext()设置身份验证对象.setAuthentication(身份验证)会导致&#34;错误的凭据&#34;错误页面。

我想了解为什么在我对令牌进行身份验证后未调用我的控制器。除此之外,还有一个&#34; Spring&#34;存储令牌而不是将其存储在Map中的方法,如SecurityContextRepository的自定义实现?

我非常感谢任何提示!

2 个答案:

答案 0 :(得分:3)

可能会有点晚,但我遇到同样的问题并添加:

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

到我的AbstractAuthenticationProcessingFilter实现就可以了。

答案 1 :(得分:0)

在构造函数中使用 setContinueChainBeforeSuccessfulAuthentication(true)