【问题标题】:How to manage session with spring security based on request type?如何根据请求类型管理与 Spring Security 的会话?
【发布时间】:2020-01-31 08:01:19
【问题描述】:

我想根据我的请求类型配置网络安全层。

如果请求以 /rest 开头,那么它应该使用带有无状态会话管理的基本身份验证,而对于登录身份验证,它应该使用带有状态会话管理的 CSRF。

我试过下面的代码。

@Override
protected void configure(HttpSecurity http) throws Exception 
{
    http
        .authorizeRequests()
        .antMatchers("/rest/**").hasRole("SUPER_ADMIN") 
        .anyRequest().fullyAuthenticated()
        .and()
        .sessionManagement()
        .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
        .and()
        .httpBasic()
        .authenticationEntryPoint(authenticationEntryPoint)
        .and()
        .formLogin().and().logout().permitAll();
}

它适用于基本身份验证,但不适用于登录请求,因为会话不是有状态的。谁能帮我配置 Spring 安全性。我是 Spring 安全新手。

【问题讨论】:

    标签: java spring spring-boot spring-mvc spring-security


    【解决方案1】:

    你需要
    1. Rest API 需要通过基本认证进行认证
    2.您的Web应用程序通过表单登录进行身份验证。
    在这两种情况下,授权都是另一部分,您可以根据自己的要求进行设置。

    让我解释一下你的方法有什么问题。通过您的方法,您只能从一种配置中实现一个身份验证入口点。即,您无法实现多个身份验证入口点。

    现在您的第一个要求是实现多个身份验证入口点。
    1. 对于 Rest API 资源 -- 通过 HttpBasicAuthentication 进行身份验证 for antMatcher /rest/**
    2. WebApp 资源 -- Form Login 认证 /rest/**以外的antMatcher

    实现这一目标
    1.你需要有不同配置顺序和不同antMatcher模式的WebSecurityConfigurerAdapter的实现。
    2.每个配置的顺序很重要。
    - 通配符模式(/**) 应放在最后一个订单
    - 非通配符模式或受限模式(/rest/**) 应优先放置
    3. 由于这些配置类是注解 @EnableWebSecurity 的类的静态和内部类,因此在使用 @bean 定义 bean 和使用 @Autowired 自动装配时应小心。

    注意:
    大多数人都会犯错误,因为没有为 authorizeRequest() 定义 antmather
    如果第一次配置@Order(1)类配置如下
    http.authorizeRequests()
    第二个配置将成为死配置,因为
    http.authorizeRequests() => http.antMatcher("/**").authorizeRequests()
    并且所有 URL 都将仅配置为仅用于第一次配置。

    请参阅下面给出的代码以更好地理解。

    @Configuration
    @EnableWebSecurity
    public class SpringSecurityConfiguration
    {
        @Bean
        public PasswordEncoder passwordEncoder() 
        {
            return new BCryptPasswordEncoder();
        }
    
        @Configuration
        @Order(1)
        public static class BasicAuthSecurityConfig extends WebSecurityConfigurerAdapter
        {
            @Autowired
            private PasswordEncoder passwordEncoder;
    
            @Autowired
            public void configureInMemoryAuthentication(AuthenticationManagerBuilder auth) throws Exception
            {
                auth.inMemoryAuthentication()
                        .withUser("superadmin")
                        .password(passwordEncoder.encode("superadmin@123#"))
                        .roles("SUPER_ADMIN");
            }
    
            @Override
            protected void configure(HttpSecurity http) throws Exception
            {
                http.csrf().disable()
                    .antMatcher("/rest/**")
                        .authorizeRequests()
                    .antMatchers("/rest/**").hasRole("SUPER_ADMIN")
                .and().httpBasic();
    
                http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
            }
        }
    
        @Configuration
        @Order(2)
        public static class LoginFormSecurityConfig extends WebSecurityConfigurerAdapter
        {
            @Autowired
            private PasswordEncoder passwordEncoder;
    
            @Autowired
            public void configureInMemoryAuthentication(AuthenticationManagerBuilder auth) throws Exception
            {
                auth.inMemoryAuthentication()
                        .withUser("user")
                        .password(passwordEncoder.encode("user@123#"))
                        .roles("USER");
            }
    
            @Override
            protected void configure(HttpSecurity http) throws Exception
            {
                http
                    .antMatcher("/**") //wild card i.e, allow all (But already /rest/** is filtered by 1st config)
                        .authorizeRequests()
                    .antMatchers("/resources/**").permitAll()
                    .antMatchers("/**").authenticated()
                .and().formLogin()
                    .defaultSuccessUrl("/app/user/dashboard")
                .and().exceptionHandling()
                    .accessDeniedPage("/403")
                .and().logout()
                    .invalidateHttpSession(true);
    
                http.sessionManagement().maximumSessions(1).expiredUrl("/login?expired");
            }
        }
    }
    

    此问题要求针对不同的身份验证过滤器使用不同的 URL 集(/rest/** 和 other than /rest/**)。这里用户(用于基本身份验证和表单登录)可以针对单个表(例如 user_details)或多个表(例如 api_users 和 web_users)进行身份验证

    如果您的要求是没有不同的 URL 集,但两组用户说 customer 和 employees(staff) 都在访问同一个应用程序,但他们需要针对不同的表进行身份验证(比如用户和客户表)在这种情况下,请参考我的另一个答案Spring Security user authentication against customers and employee table

    【讨论】:

    • 是的,它奏效了。非常感谢您提供了很好的描述性答案。
    【解决方案2】:

    您必须允许用户在没有身份验证的情况下访问登录页面,您可以对静态页面进行同样的操作。见下面的配置。

    @Configuration
    @EnableWebSecurity
    public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http
                .authorizeRequests()
                    .antMatchers("/", "/home").permitAll()
                    .anyRequest().authenticated()
                    .and()
                .formLogin()
                    .loginPage("/login")
                    .permitAll()
                    .and()
                .logout()
                    .permitAll();
        }
    
        @Bean
        @Override
        public UserDetailsService userDetailsService() {
            UserDetails user =
                 User.withDefaultPasswordEncoder()
                    .username("user")
                    .password("password")
                    .roles("USER")
                    .build();
    
            return new InMemoryUserDetailsManager(user);
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2011-09-18
      • 2016-04-26
      • 2011-01-09
      • 2011-08-19
      • 2013-12-01
      • 1970-01-01
      • 2012-05-25
      • 2013-05-27
      相关资源
      最近更新 更多