具有spring security的多个自定义身份验证

时间:2017-09-15 11:26:19

标签: spring authentication spring-security

我有一个spring应用程序,它使用自定义身份验证筛选器说filter1来授权请求​​,此筛选器使用身份验证管理器进行身份验证,适用于应用程序中的所有URL。

现在,我想实现一个不同的身份验证过滤器说filter2,它必须使用url(/ api /)授权特殊类型的请求。这就是具有url的所有请求(/ api / **)必须使用filter2。

以下是我为此目的而尝试的代码。

public class SecurityAppConfig {

@Configuration
@Order(1)
public static class APISecurityConfig extends WebSecurityConfigurerAdapter {

private CustomAuthenticationManager1 manager1 = new CustomAuthenticationManager1();

@Override
protected void configure(HttpSecurity http) throws Exception {
  http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
      .formLogin().disable().csrf().disable().cors().disable().logout().disable();

  if (manager1 != null) {
    http.addFilterAfter(new Filter1(manager1),
        AnonymousAuthenticationFilter.class);

  }

}
}


@Configuration
@Order(2)
public static class OtherApiSecurityConfig extends WebSecurityConfigurerAdapter {

private AuthenticationManager2 manager2 = new AuthenticationManager2();

@Override
protected void configure(HttpSecurity http) throws Exception {
  http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
      .formLogin().disable().csrf().disable().cors().disable().logout().disable();

  if (manager2 != null) {
    http.antMatchers("/api/**").addFilterAfter(new Filter2(manager2),
        AnonymousAuthenticationFilter.class);
  }
}
}

}

在应用程序启动时,过滤器都会向其管理员注册,但是当这个(“/ api / **”)请求到来时,它会进入第一个过滤器进行身份验证,但永远不会进入第二个过滤器。如果我删除了第一个过滤器,那么它可以正常工作但是会覆盖其他api请求的过滤器。

以下是我实施管理员和过滤器的方式

public class Filter1 extends AbstractAuthenticationProcessingFilter {
  //implementation omitted for brevity.
}

public class Filter2 extends AbstractAuthenticationProcessingFilter {
  //implementation omitted for brevity.
}

public class AuthenticationManager1 implements AuthenticationManager {
   //implementation omitted for brevity.
}

 public class AuthenticationManager2 implements AuthenticationManager {
   //implementation omitted for brevity.
}

有关如何使其正常工作的任何想法。

1 个答案:

答案 0 :(得分:4)

我认为你的案子不需要两个配置。我不明白为什么你需要实现自己的身份验证管理器,甚至其中两个。我想你应该使用共享身份验证管理器,实现自己的AuthenticationProvider(每种身份验证类型一个),并实现自己的身份验证令牌。除此之外,由于您使用AbstractAuthenticationProcessingFilter作为过滤器的基类 - 您可以将filterProcessesUrl设置为其中,因此您的过滤器知道应该应用哪个URL。所以,简而言之:

身份验证令牌:

public class MyAuth1AuthenticationToken extends AbstractAuthenticationToken {
    // Implementation depends on you auth scheme (you can look on 
    // `UsernamePasswordAuthenticationToken` for example)
}

public class MyAuth2AuthenticationToken extends AbstractAuthenticationToken {
    // ...
}

身份验证提供商:

public class MyAuth1AuthenticationProvider implements AuthenticationProvider {
    @Override
    public Authentication authenticate(Authentication authentication)
        throws AuthenticationException {
        // Implementation really depends on you auth scheme (you can look on 
        // `AbstractUserDetailsAuthenticationProvider` for example)
    }        

    @Override
    public boolean supports(Class<?> authentication) {
        // By this we're saying that this auth provider is responsible for our MyAuth1 auth request 
        return (MyAuth1AuthenticationToken.class.isAssignableFrom(authentication));
    }
}

public class MyAuth2AuthenticationProvider implements AuthenticationProvider {
    @Override
    public Authentication authenticate(Authentication authentication)
        throws AuthenticationException {
        // ...
    }        

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

过滤器:

public class Auth1Filter extends AbstractAuthenticationProcessingFilter {

    public Auth1Filter(AuthenticationManager authManager, String defaultFilterProcessesUrl) {
        super(defaultFilterProcessesUrl);
        setAuthenticationManager(authManager);
    }

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

        // extract user info here
        // ...

        // populate auth request with your info
        MyAuth1AuthenticationToken authRequest = new MyAuth1AuthenticationToken(...);

        // authenticate
        return this.getAuthenticationManager().authenticate(authRequest);
    }
}

public class Auth2Filter extends AbstractAuthenticationProcessingFilter {

    public Auth2Filter(AuthenticationManager authManager, String defaultFilterProcessesUrl) {
        super(defaultFilterProcessesUrl);
        setAuthenticationManager(authManager);
    }

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

        // extract user info here
        // ...

        // populate auth request with your info
        MyAuth2AuthenticationToken authRequest = new MyAuth1AuthenticationToken(...);

        // authenticate
        return this.getAuthenticationManager().authenticate(authRequest);
    }
}

安全配置:

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
public void configure(AuthenticationManagerBuilder auth) throws Exception
{
    // registering our providers
    auth
        .authenticationProvider(new MyAuth1AuthenticationProvider())
        .authenticationProvider(new MyAuth2AuthenticationProvider());   
}

    @Override
    protected void configure(HttpSecurity http) throws Exception {
       http
           .sessionManagement()
           .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
           .and()
           .formLogin().disable()
           .csrf().disable()
           .cors().disable()
           .logout().disable();

        AuthenticationManager authManager = http.getSharedObject(AuthenticationManager.class);

        http.addFilterAfter(new Auth1Filter(authManager, "/**"), BasicAuthenticationFilter.class);
        http.addFilterAfter(new Auth2Filter(authManager, "/api/**"), BasicAuthenticationFilter.class);
    }
}

希望它有所帮助。