使用 Spring security Javaconfig 进行基本和基于表单的身份验证

Posted

技术标签:

【中文标题】使用 Spring security Javaconfig 进行基本和基于表单的身份验证【英文标题】:Basic and form based authentication with Spring security Javaconfig 【发布时间】:2013-09-14 19:15:43 【问题描述】:

我正在尝试为不同的 url 模式定义两种不同的安全配置,其中一种使用表单登录,另一种使用 api 的基本身份验证。

我正在寻找的解决方案类似于此处解释的解决方案http://meera-subbarao.blogspot.co.uk/2010/11/spring-security-combining-basic-and.html,但我想使用 java config 来完成。

提前致谢。

这是我目前的配置:

@Configuration
@EnableWebSecurity
public class AppSecurityConfig extends WebSecurityConfigurerAdapter 

    @Autowired
    private UserService userService;

    @Override
    protected void registerAuthentication(AuthenticationManagerBuilder auth) throws Exception 
        auth.userDetailsService(userService);
    

    @Override
    public void configure(WebSecurity web) throws Exception 
        // Ignore any request that starts with "/resources/".
        web.ignoring().antMatchers("/resources/**");
    

    @Override
    protected void configure(HttpSecurity http) throws Exception 
        http.authorizeUrls().antMatchers("/", "/index", "/user/**", "/about").permitAll()
        .antMatchers("/admin/**").hasRole("ADMIN")
        .anyRequest().authenticated()
        .and().formLogin()
        .loginUrl("/login")
        .failureUrl("/login-error")
        .loginProcessingUrl("/security_check")
        .usernameParameter("j_username").passwordParameter("j_password")
        .permitAll();

        http.logout().logoutUrl("/logout");
        http.rememberMe().rememberMeServices(rememberMeServices()).key("password");
    

    @Bean
    public RememberMeServices rememberMeServices() 
        TokenBasedRememberMeServices rememberMeServices = new TokenBasedRememberMeServices("password", userService);
        rememberMeServices.setCookieName("cookieName");
        rememberMeServices.setParameter("rememberMe");
        return rememberMeServices;
    

【问题讨论】:

你看到了什么结果? 目前我只有表单身份验证,我找不到如何将基本身份验证添加到 /api/* 之类的 url 模式 【参考方案1】:

显然,随着 Spring 的更新,它们的适用性往往会逐渐减弱。运行 spring cloud starter security 1.4.0.RELEASE 这是我的解决方案。我的用例有点不同,因为我尝试使用基本身份验证进行云配置并使用带有 spring 会话的网关在所有其他实例中通过身份验证来保护刷新端点。

@EnableWebSecurity
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter 

    @Autowired
    public void configureGlobal1(AuthenticationManagerBuilder auth) throws Exception 
        //try in memory auth with no users to support the case that this will allow for users that are logged in to go anywhere
        auth.inMemoryAuthentication();
    

    @Override
    protected void configure(HttpSecurity http) throws Exception 
        http
            .httpBasic()
                .disable()
            .authorizeRequests()
                .antMatchers(HttpMethod.POST, "/user").permitAll()
                .anyRequest().authenticated()
                .and()
            .csrf().disable();
    

    @Bean
    public BCryptPasswordEncoder encoder() 
        return new BCryptPasswordEncoder(11);
    

    @Configuration
    @Order(1)
    public static class ApiWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter 

        @Autowired
        private AuthenticationProvider customAuthenticationProvider;

        @Autowired
        protected void configureGlobal2(AuthenticationManagerBuilder auth) throws Exception 
            auth
                    .authenticationProvider(customAuthenticationProvider);
        

        @Override
        protected void configure(HttpSecurity http) throws Exception 
            http
                .httpBasic()
                    .and()
                .authorizeRequests()
                    .antMatchers(HttpMethod.POST, "/refresh").hasRole("SUPER")
                    .and()
                .csrf().disable();
        
    

请参阅 spring 安全文档以获得进一步说明:Spring Security

基本思想是@Order 注释将指示身份验证方案的运行顺序。没有@Order 意味着它是最后一个。如果 authorizeRequests() 部分无法匹配传入的 URL,则该配置将通过,下一个将尝试身份验证。这将一直持续到身份验证成功或失败。

【讨论】:

【参考方案2】:

这里的其他答案相对较旧,例如我在 Spring 4 中找不到authorizeUrls

在 SpringBoot 1.4.0 / Spring 4 中,我已经实现了这样的基本/表单登录:

@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter

   protected void configure (HttpSecurity aHttp) throws Exception
       
      aHttp.authorizeRequests ().antMatchers (("/api/**")).fullyAuthenticated ().and ().httpBasic ();

      aHttp.formLogin ()
         .loginPage ("/login").permitAll ()
         .and ().logout ().permitAll ();
   

可能有更优雅的方式来编写这个 - 我仍在努力了解这个构建器是如何在序列等方面工作的。但这行得通。

【讨论】:

这对我不起作用 - 访问 /api/ 的尝试被重定向到登录表单而不是基本身份验证。 @JamesBaker - OP 从来没有提到他需要被提示进行基本身份验证......但是基本身份验证,上面的,确实有效。如果您使用 HTTP 客户端并在您的请求中发送基本身份验证凭据,它确实有效。【参考方案3】:

您可以通过在第一个配置中的 http 之后添加 .antMatcher("/api/**") 来解决此问题,以仅管理 /api 网址。您必须在第一个适配器上安装它:

http
    .antMatcher("/api/*")
    .authorizeRequests()
        .antMatchers("^/api/.+$").hasRole("ADMIN")
    ....

【讨论】:

【参考方案4】:

我找到的解决方案是在第一个类中创建另一个扩展 WebSecurityConfigurerAdapter 的类,如https://github.com/spring-projects/spring-security-javaconfig/blob/master/samples-web.md#sample-multi-http-web-configuration 所述

我的解决方法如下:

@Configuration
@EnableWebSecurity
public class AppSecurityConfig extends WebSecurityConfigurerAdapter 

    @Autowired
    private UserService userService;

    @Override
    protected void registerAuthentication(AuthenticationManagerBuilder auth) throws Exception 
        auth.userDetailsService(userService);
    

    @Override
    public void configure(WebSecurity web) throws Exception 
        // Ignore any request that starts with "/resources/".
        web.ignoring().antMatchers("/resources/**");
    

    @Override
    protected void configure(HttpSecurity http) throws Exception 
        http.authorizeUrls().antMatchers("/", "/index", "/user/**", "/about").permitAll()
            .antMatchers("/admin/**").hasRole("ADMIN")
            .anyRequest().authenticated()
            .and().formLogin()
            .loginUrl("/login")
            .failureUrl("/login-error")
            .loginProcessingUrl("/security_check")
            .usernameParameter("j_username").passwordParameter("j_password")
            .permitAll();

        http.logout().logoutUrl("/logout");
        http.rememberMe().rememberMeServices(rememberMeServices()).key("password");
    

    @Bean
    public RememberMeServices rememberMeServices() 
        TokenBasedRememberMeServices rememberMeServices = new TokenBasedRememberMeServices("password", userService);
        rememberMeServices.setCookieName("cookieName");
        rememberMeServices.setParameter("rememberMe");
        return rememberMeServices;
    

    @Configuration
    @Order(1)
    public static class ApiWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter 

        @Override
        protected void registerAuthentication(AuthenticationManagerBuilder auth) throws Exception 
            auth.inMemoryAuthentication().withUser("api").password("pass").roles("API");
        

        protected void configure(HttpSecurity http) throws Exception 
            http.authorizeUrls()
                .antMatchers("/api/**").hasRole("API")
                .and()
                .httpBasic();
        
    

【讨论】:

【参考方案5】:

我会说只是这样做。使用 authorizeUrls() 指定第二行,但用于基本身份验证所需的 URL。而不是formLogin() 使用httpBasic()

@Override
protected void configure(HttpSecurity http) throws Exception 
    http.authorizeUrls().antMatchers("/", "/index", "/user/**", "/about").permitAll()
    .antMatchers("/admin/**").hasRole("ADMIN")
    .anyRequest().authenticated()
    .and().formLogin()
    .loginUrl("/login")
    .failureUrl("/login-error")
    .loginProcessingUrl("/security_check")
    .usernameParameter("j_username").passwordParameter("j_password")
    .permitAll();

    http.authorizeUrls().antMatchers("/api/*").hasRole("YOUR_ROLE_HERE").and().httpBasic();

    http.logout().logoutUrl("/logout");
    http.rememberMe().rememberMeServices(rememberMeServices()).key("password");

类似的东西应该可以。

链接:HttpSecurityHttpBasicConfgurer

【讨论】:

没用,api 声称两次调用 authorizeUrls() 会覆盖之前的调用,因此可能无法这样做

以上是关于使用 Spring security Javaconfig 进行基本和基于表单的身份验证的主要内容,如果未能解决你的问题,请参考以下文章

Spring Framework,Spring Security - 可以在没有 Spring Framework 的情况下使用 Spring Security?

仅使用 Spring-Security(或)Spring 进行授权

在使用 Oauth、SAML 和 spring-security 的多租户的情况下从 spring-security.xml 中获取错误

Spring security:Spring security 如何在 SessionRegistry 中注册新会话?

未调用 Spring Security j_spring_security_check

使用 spring-session 和 spring-cloud-security 时,OAuth2ClientContext (spring-security-oauth2) 不会保留在 Redis