具有Spring Security的多重自定义身份验证

use*_*611 1 authentication spring spring-security

我有一个spring应用程序,它使用自定义的身份验证过滤器,例如filter1来授权请求​​,此过滤器使用身份验证管理器进行身份验证,并且适用于应用程序中的所有url。

现在,我想实现一个不同的身份验证过滤器,例如filter2,该过滤器必须使用url(/ api /)授权特殊的请求类型。这就是所有具有(/ api / **)之类的url的请求都必须使用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);
  }
}
}

}
Run Code Online (Sandbox Code Playgroud)

在应用启动时,两个过滤器都已向其经理注册,但是当此(“ / 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.
}
Run Code Online (Sandbox Code Playgroud)

关于如何使它起作用的任何想法。

Lef*_*hik 5

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

Authentication Tokens:

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

public class MyAuth2AuthenticationToken extends AbstractAuthenticationToken {
    // ...
}
Run Code Online (Sandbox Code Playgroud)

Authentication Providers:

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));
    }
}
Run Code Online (Sandbox Code Playgroud)

Filters:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

Security Config:

@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);
    }
}
Run Code Online (Sandbox Code Playgroud)

Hope it helps.