多个WebSecurityConfigurerAdapter:一个作为库,在其他用户中可以添加自己的安全访问权限

mar*_*rio 5 spring spring-security stormpath

我正在创建一个Spring Security配置,以供任何想要创建由Spring Security保护的Stormpath Spring应用程序的开发人员用作库.

对于我有子类WebSecurityConfigurerAdapter,定义了Stormpath访问控件configure(HttpSecurity)以及与Stormpath AuthenticationProvider借助于configure(AuthenticationManagerBuilder).所有这些都可以在这个抽象类及其具体的子类中看到:

@Order(99)
public abstract class AbstractStormpathWebSecurityConfiguration extends WebSecurityConfigurerAdapter {

    //Removed properties and beans for the sake of keeping focus on the important stuff

    /**
     * The pre-defined Stormpath access control settings are defined here.
     *
     * @param http the {@link HttpSecurity} to be modified
     * @throws Exception if an error occurs
     */
    protected void configure(HttpSecurity http, AuthenticationSuccessHandler successHandler, LogoutHandler logoutHandler)
            throws Exception {

        if (loginEnabled) {
            http
                    .formLogin()
                    .loginPage(loginUri)
                    .defaultSuccessUrl(loginNextUri)
                    .successHandler(successHandler)
                    .usernameParameter("login")
                    .passwordParameter("password");
        }

        if (logoutEnabled) {
            http
                    .logout()
                    .invalidateHttpSession(true)
                    .logoutUrl(logoutUri)
                    .logoutSuccessUrl(logoutNextUri)
                    .addLogoutHandler(logoutHandler);

        }

        if (!csrfProtectionEnabled) {
            http.csrf().disable();
        } else {
            //Let's configure HttpSessionCsrfTokenRepository to play nicely with our Controllers' forms
            http.csrf().csrfTokenRepository(stormpathCsrfTokenRepository());
        }
    }

    /**
     * Method to specify the {@link AuthenticationProvider} that Spring Security will use when processing authentications.
     *
     * @param auth the {@link AuthenticationManagerBuilder} to use
     * @param authenticationProvider the {@link AuthenticationProvider} to whom Spring Security will delegate authentication attempts
     * @throws Exception if an error occurs
     */
    protected void configure(AuthenticationManagerBuilder auth, AuthenticationProvider authenticationProvider) throws Exception {
        auth.authenticationProvider(authenticationProvider);
    }
}

@Configuration
public class StormpathWebSecurityConfiguration extends AbstractStormpathWebSecurityConfiguration {

    //Removed beans for the sake of keeping focus on the important stuff

    @Override
    protected final void configure(HttpSecurity http) throws Exception {
        configure(http, stormpathAuthenticationSuccessHandler(), stormpathLogoutHandler());
    }

    @Override
    protected final void configure(AuthenticationManagerBuilder auth) throws Exception {
        configure(auth, super.stormpathAuthenticationProvider);
    }
}
Run Code Online (Sandbox Code Playgroud)

简而言之,我们基本上定义了我们的登录和注销机制,并整合了我们的CSRF代码,以便与Spring Security的代码很好地配合.

到目前为止一切正常.

但这只是"库",我们希望用户在其上构建自己的应用程序.

因此,我们创建了一个Sample应用程序来演示用户将如何使用我们的库.

基本上用户会想要创建自己的WebSecurityConfigurerAdapter.像这样:

@EnableStormpathWebSecurity
@Configuration
@ComponentScan
@PropertySource("classpath:application.properties")
@Order(1)
public class SpringSecurityWebAppConfig extends WebSecurityConfigurerAdapter {

    /**
     * {@inheritDoc}
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().antMatchers("/restricted").fullyAuthenticated();
    }

}
Run Code Online (Sandbox Code Playgroud)

如果确实需要这样,WebApplicationInitializer看起来像这样:

public class WebAppInitializer implements WebApplicationInitializer {

    @Override
    public void onStartup(ServletContext sc) throws ServletException {

        AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
        context.register(SpringSecurityWebAppConfig.class);
        context.register(StormpathMethodSecurityConfiguration.class);
        sc.addListener(new ContextLoaderListener(context));

        ServletRegistration.Dynamic dispatcher = sc.addServlet("dispatcher", new DispatcherServlet(context));
        dispatcher.setLoadOnStartup(1);
        dispatcher.addMapping("/");

        //Stormpath Filter
        FilterRegistration.Dynamic filter = sc.addFilter("stormpathFilter", new DelegatingFilterProxy());
        EnumSet<DispatcherType> types =
                EnumSet.of(DispatcherType.ERROR, DispatcherType.FORWARD, DispatcherType.INCLUDE, DispatcherType.REQUEST);
        filter.addMappingForUrlPatterns(types, false, "/*");

        //Spring Security Filter
        FilterRegistration.Dynamic securityFilter = sc.addFilter(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME, DelegatingFilterProxy.class);
        securityFilter.addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class), false, "/*");
    }
}
Run Code Online (Sandbox Code Playgroud)

所有这些代码都正确启动.如果我去,localhost:8080我看到欢迎屏幕.如果我去,localhost:8080/login我会看到登录屏幕.但是,如果我去,localhost:8080/restricted我应该被重定向到登录页面,因为我们有这条线:http.authorizeRequests().antMatchers("/restricted").fullyAuthenticated();.但是我正在看Access Denied页面.

然后,如果我在App的访问控制中添加登录URL,如下所示:

protected void configure(HttpSecurity http) throws Exception {
    http
            .formLogin().loginPage("/login")
            .and()
            .authorizeRequests().antMatchers("/restricted").fullyAuthenticated();
}
Run Code Online (Sandbox Code Playgroud)

它现在将我重定向到登录页面,但是一旦我提交凭据,我就会遇到CSRF问题,这意味着我们所有的配置实际上都不是此过滤器链的一部分.

当我调试它时,似乎每个WebApplicationInitializer都有自己的实例和自己的Filter Chain.我希望它们能以某种方式连接起来,但似乎它实际上并没有发生......

有没有人尝试过这样的事情?

顺便说一句:作为一种解决方法,用户可以public class SpringSecurityWebAppConfig extends StormpathWebSecurityConfiguration代替SpringSecurityWebAppConfig extends WebSecurityConfigurerAdapter.这种方式可行但我希望用户拥有纯粹的Spring Security代码并从我们StormpathWebSecurityConfiguration与该目标的分歧中扩展.

所有代码都可以在这里看到.Spring的Stormpath Spring Security库正在进行中extensions/spring/stormpath-spring-security-webmvc.使用该库的示例应用程序位于examples/spring-security-webmvc.

运行起来非常简单......您只需要按照此处的说明注册到Stormpath .然后你可以签出spring_security_extension_redirect_to_login_not_working分支并启动示例应用程序,如下所示:

$ git clone git@github.com:mrioan/stormpath-sdk-java.git
$ git checkout spring_security_extension_redirect_to_login_not_working
$ mvn install -DskipTests=true
$ cd examples/spring-security-webmvc
$ mvn jetty:run
Run Code Online (Sandbox Code Playgroud)

然后,您可以localhost:8080/restricted看到您没有被重定向到登录页面.

很感谢任何形式的帮助!

Ran*_*niz 3

WebSecurityConfigurer根据我的经验,启动时多个 s 扰乱安全配置会出现问题。

解决这个问题的最佳方法是使您的库配置成为SecurityConfigurerAdapters可以在适当的地方应用的配置。

public class StormpathHttpSecurityConfigurer
        extends AbstractStormpathWebSecurityConfiguration
        implements SecurityConfigurer<DefaultSecurityFilterChain, HttpSecurity> {

    //Removed beans for the sake of keeping focus on the important stuff

    @Override
    protected final void configure(HttpSecurity http) throws Exception {
        configure(http, stormpathAuthenticationSuccessHandler(), stormpathLogoutHandler());
    }
}

public class StormpathAuthenticationManagerConfigurer
        extends AbstractStormpathWebSecurityConfiguration
        implements SecurityConfigurer<AuthenticationManager, AuthenticationManagerBuilder> {

    //Removed beans for the sake of keeping focus on the important stuff

    @Override
    protected final void configure(AuthenticationManagerBuilder auth) throws Exception {
        configure(auth, super.stormpathAuthenticationProvider);
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,您的用户可以apply使用自己的配置:

@EnableStormpathWebSecurity
@Configuration
@ComponentScan
@PropertySource("classpath:application.properties")
@Order(1)
public class SpringSecurityWebAppConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .antMatchers("/restricted").fullyAuthenticated()
                .and()
            .apply(new StormPathHttpSecurityConfigurer(...))
        ;
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.apply(new StormPathAuthenticationManagerConfigurer(...));
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 这实际上就是我们最终实现的方式。为了使更干净,我们静态导入了配置器。事情最终看起来像这样:https://github.com/stormpath/stormpath-sdk-java/blob/master/examples/spring-security-spring-boot-webmvc-bare-bones/src/main/java/com/ stormpath/spring/boot/examples/SpringSecurityWebAppConfig.java (2认同)