如何在运行时使用 spring 安全性切换安全模型?

How to switch security model in runtime with spring security?

如何在运行时切换安全模型,以便

  1. 现有的 spring 安全组件可以生成 Authentication,并且
  2. 一个现有的 spring 安全组件可以验证 Authentication

我想我解决了 (2) 但不太明白 (1)


Spring 安全配置

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().antMatchers("/**").authenticated().and()
            .addFilterBefore(switchingFilter);
    }

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

    @Bean
    public SwitchingAuthenticationProvider switchingAuthenticationProvider() {
        return new SwitchingAuthenticationProvider();
    }

    @Bean
    public SwitchingFilter switchingFilter() {
        return new SwitchingFilter();
    }
}

SwitchingAuthenticationProvider 很简单:只需委托给其他人 AuthenticationProvder(即 LDAP/OAUTH2 或其他)

(灵感来自 Switching authentication approaches at runtime with Spring Security)。

public class SwitchingAuthenticationProvider implements AuthenticationProvider {

    private AuthenticationProvider[] authProviders = // ...

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        return authProvider[i].authenticate(authentication);
    }
}

但是是什么创造了 Authentication?据我了解,一种选择是让 GenericFilterBean 创建 Authentication ,如下所示。

public class SwitchingFilter extends GenericFilterBean {

    private AuthProviderService authProviders = // ...

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        Authentication authentication = authProviders.getAuthentication(request);
        SecurityContextHolder.getContext().setAuthentication(authentication);
        filterChain.doFilter(request, response);
        SecurityContextHolder.getContext().setAuthentication(null);
   }
}

... 其中 AuthProviderService 将委托给创建 authentication 的对象。但是我如何插入它,例如 HttpSecurity#httpBasic()HttpSecurity#openIdLogin()?


奖金问题:HttpSecurity#authenticationProvider(..)AuthenticationManagerBuilder.authenticationProvider(..) 有什么区别?

似乎 Filter 负责创建 Authentication (不确定是否还有其他内容也)。

AnonymousAuthenticationFilter为例

public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
        throws IOException, ServletException {

    if (SecurityContextHolder.getContext().getAuthentication() == null) {
        SecurityContextHolder.getContext().setAuthentication(
                createAuthentication((HttpServletRequest) req));
}

类似我认为SwitchingFilter应该类似于SwitchingAuthenticationProvider

public class SwitchingFilter extends GenericFilterBean {

    private Filter[] filters = // ...

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        filters[i].doFilter(request, response, chain);
        // do filterChain.doFilter(request, response); ??
   }
}

.. 一些选择合适索引的机制i