java - 如何根据请求类型使用Spring Security管理 session ?

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

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

如果请求以 /rest 开头,则应使用带有无状态 session 管理的基本身份验证,对于登录身份验证,则应使用带有状态 session 管理的 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();
}

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

最佳答案

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

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

现在来满足您的第一个要求:实现多个身份验证入口点。
1. 对于 Rest API 资源 -- 通过 HttpBasicAuthentication 进行身份验证 针对 antMatcher /rest/**
2. 对于 WebApp 资源 - 通过表单登录进行身份验证 /rest/**

之外的 antMatcher

实现这一目标
1. 您需要实现不同配置顺序和不同antMatcher模式的WebSecurityConfigurerAdapter
2. 每个配置的顺序很重要。
- 通配符模式(/**) 应放在最后一个订单
- 非通配符模式或限制模式(/rest/**)应放在第一位
3. 由于这些配置类是静态的,并且是注释为 @EnableWebSecurity 的类的内部类,因此在使用 @bean 定义 bean 和使用 @ Autowiring 时应该小心自动连线

Note:
Most of people makes mistake by not defining antmather for authorizeRequest()
If first configuration @Order(1) class is configured as below
http.authorizeRequests()
2nd configuration will become dead configuration because
http.authorizeRequests() => http.antMatcher("/**").authorizeRequests()
And all URL's will be configured only for first configuration only.

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

@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/**/rest/** 除外)。这里,用户(对于基本身份验证和表单登录)可以根据单个表(例如 user_details)或多个表(例如 api_usersweb_users)进行身份验证

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

关于java - 如何根据请求类型使用Spring Security管理 session ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58194759/

相关文章:

java - 如何在 AOP 中围绕注释自定义错误消息?

java - Spring Security中如何保证同一个账号不被两个不同的人同时登录?

Spring Jsps 和跳转到 anchor

java - 无法在 weblogic 12c 上部署 Spring Boot 应用程序(非 Web)war 文件

java - Code smell sonarLint - 为静态字段赋值

java - h :commandButton not working within PrimeFaces p:dataTable

java - Spring Swagger2集成ServletContext Autowiring 问题

java - 从 JUnit 单元测试的角度来看 Java EE 应用程序中 Ant 构建文件之间的任务层次结构和分布

regex - Spring-Boot @RequestMapping 和@PathVariable 正则表达式匹配

angularjs - Access-Control-Allow-Origin 中的多个 ip 不起作用