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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18729752/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 10:32:44  来源:igfitidea点击:

Basic and form based authentication with Spring security Javaconfig

javaspringspring-security

提问by Adrian Lopez

I'm trying to define two different security configurations for different url patterns, one of them using form login and another one using basic authentication for an api.

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

The solution I'm looking for is similar to the one explained here http://meera-subbarao.blogspot.co.uk/2010/11/spring-security-combining-basic-and.htmlbut I would like to do it using java config.

我正在寻找的解决方案类似于这里解释的解决方案http://meera-subbarao.blogspot.co.uk/2010/11/spring-security-combining-basic-and.html但我想这样做使用java配置。

Thanks in advance.

提前致谢。

This is the configuration I currently have:

这是我目前的配置:

@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;
    }
}

采纳答案by Adrian Lopez

The solution I found was to create another class extending WebSecurityConfigurerAdapter inside the first one, like is described https://github.com/spring-projects/spring-security-javaconfig/blob/master/samples-web.md#sample-multi-http-web-configuration

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

My solution is as follows:

我的解决方案如下:

@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();
        }
    }
}

回答by M. Deinum

I would say by simply doing it. Specify a second line with authorizeUrls() but for your URLs that are needed with basic authentication. Instead of formLogin()use httpBasic()

我会说简单地做。使用 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");
}

Something like that should work.

这样的事情应该有效。

Links: HttpSecurity, HttpBasicConfgurer.

链接:HttpSecurityHttpBasicConfgurer

回答by perenono

You can solve it by adding .antMatcher("/api/**")just after httpin your first config to manage only /apiurls. You must have it on the first adapter:

您可以通过在第一个配置中添加.antMatcher("/api/**")just afterhttp来仅管理/apiurl来解决它。您必须在第一个适配器上安装它:

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

回答by ETL

The other answers in here are relatively old and for example, I can't find authorizeUrlsin Spring 4.

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

In SpringBoot 1.4.0 / Spring 4, I've implemented the basic/form login like this:

在 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 ();
   }
}

There may be more ellegant ways of writing this - I'm still working on understanding how this builder works in terms of sequence and so forth. But this worked.

可能有更优雅的写法——我仍在努力理解这个构建器在序列等方面是如何工作的。但这奏效了。

回答by Ceekay

Obviously As Spring updates these tend to fade in their applicability. Running spring cloud starter security 1.4.0.RELEASE this is my solution. My use case was a bit different as I'm trying to secure the refresh endpoint using basic auth for cloud configuration and using a gateway with spring session to pass the authentication in all other instances.

显然,随着 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();
        }
    }
}

see the spring security docs for further clarification: Spring Security

有关进一步说明,请参阅 spring 安全文档:Spring Security

The basic idea is that the @Order annotation will dictate what order the auth schemes are run. No @Order means that it is last. If the authorizeRequests() section cannot match on the incoming URL then that configuration will pass and the next one will attempt authentication. This will proceed until authentication succeeds or fails.

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