Spring security - 指定顺序时多个httpsecurity不起作用[重复]

Posted

技术标签:

【中文标题】Spring security - 指定顺序时多个httpsecurity不起作用[重复]【英文标题】:Spring security - multiple httpsecurity not work when specify order [duplicate] 【发布时间】:2020-01-04 16:55:46 【问题描述】:

我已按照以下说明为管理员和用户创建了两个不同的 http 安全块。 docs.spring.io/spring-security-multiple-httpsecurity

如文档所述,如果 URL 不以 /aaa 开头,则将使用另一个配置进行模式。

但是当我将 @Order(1) 放在管理块时,管理页面工作正常,用户页面不会重定向到登录页面 /login/user

当我将 @Order(1) 放在用户块时,用户页面工作正常,管理页面也不会重定向到登录页面 /login/admin。

这是我的java代码

@EnableWebSecurity
public class MultiHttpSecurityConfig 

    /**
     * intercept user url
     */
    @Configuration
    @Order(1)
    public static class UserWebSecurityConfig extends WebSecurityConfigurerAdapter 
        @Autowired
        CustomAuthenticationSuccessHandler successHandler;

        @Autowired
        CustomAuthenticationFailureHandler failureHandler;

        @Autowired
        private CustomAuthenticationProvider customAuthProvider;

        @Autowired
        private CustomUserDetailsService userDetailsService;

        @Value("$my.cookie.timeout")
        private int cookieTimeOut;


        @Override
        protected void configure(HttpSecurity http) throws Exception 
            http.csrf().disable();
            http.authorizeRequests()
                .antMatchers("/css/**", "/js/**", "/images/**, /fonts/**").permitAll()
                .antMatchers("/bbb/**","/aaaa/**").hasAnyRole("USER");
            http.formLogin()
                .successHandler(successHandler)
                .failureHandler(failureHandler)
                .loginPage("/login/user").permitAll();
            http.logout().permitAll();

            http.rememberMe().key("uniqueAndSecret").tokenValiditySeconds(cookieTimeOut);
        

        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception 
            auth.authenticationProvider(customAuthProvider);
            auth.userDetailsService(userDetailsService);
        
    


    /**
     * intercept admin url
     */
    @Configuration
    public static class AdminWebSecurityConfig extends WebSecurityConfigurerAdapter 
        @Autowired
        CustomAuthenticationSuccessHandler successHandler;

        @Autowired
        CustomAuthenticationFailureHandler failureHandler;

        @Value("$my.cookie.timeout")
        private int cookieTimeOut;

        @Override
        protected void configure(HttpSecurity http) throws Exception 
            http.csrf().disable();
            http.authorizeRequests()
                .antMatchers("/css/**", "/js/**", "/images/**, /fonts/**").permitAll()
                .antMatchers("/ccc/**","/dddd").hasAnyRole("ADMIN");
            http.formLogin()
                .successHandler(successHandler)
                .failureHandler(failureHandler)
                .loginPage("/login/admin").permitAll();
            http.logout().permitAll();

            http.rememberMe().key("uniqueAndSecret").tokenValiditySeconds(cookieTimeOut);
        

        @Autowired
        public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception 
            auth.inMemoryAuthentication()
                .withUser("test").password("test").roles("ADMIN");
        
    

更新:

如下 dur 所说,关键原因是 authorizeRequests() 方法匹配 Order(1) 中的所有 url,所以我需要添加 antMatcher("/bbb/* >")** 首先在 authorizeRequests() 之前。

但 antMatcher() 只匹配一种 url ,如果我还有一种 url 要匹配,例如 "/bbb/" , "/aaa/*" ,如何实现这 ? 然后我需要再添加一个 WebSecurityConfigurerAdapter 配置? 有没有更好的方法来减少代码?

我在 spring-security SDK requestMatchers() 方法中找到了解决方案,它在 requestMatchers() 方法上方提供了一个示例。

下面是我在 Order(1) 处匹配用户网址的代码

http.csrf().disable();
            http.requestMatchers()
                .antMatchers("/bbb/**", "/aaa/**")
                .and()
                .authorizeRequests()
                .antMatchers("/**").hasAnyRole("USER");
            http.formLogin()
                .successHandler(successHandler)
                .failureHandler(failureHandler)
                .loginPage("/login/user").permitAll();
            http.logout().permitAll();

那么bbb和aaa都已经匹配好了,不需要再创建配置

但是又出现了一个问题,将用户名和密码发布到登录/用户界面时会显示“405 method not allowed”登录页面,而管理页面工作正常

我搜索了谷歌,它告诉我要禁用 csrf,但我已经禁用 csrf...

【问题讨论】:

两种配置都适用于/**(任何请求),所以使用第一个。如果您添加订单,则使用订单最低的订单。 【参考方案1】:

在我的一个项目中,我没有使用表单登录,而是实现了一个自定义 AccessDeniedHandler 和 AuthenticationEntryPoint,它可以使用我需要的一些自定义逻辑重定向到不同的登录页面。但是,loginPage() 最终也是一个 AuthenticationEntryPoint。

它们可以通过以下方式添加:

.exceptionHandling().authenticationEntryPoint(new YourCustomAuthEntryHandler()).and()
.exceptionHandling().accessDeniedHandler(new YourCustomAccessDeniedHandler())

这只是一个想法,也许值得检查一下。

此外,我认为您需要对所有请求进行身份验证,请在 authorizeRequests() 块中为两个配置添加此行:

.anyRequest().authenticated()

【讨论】:

现在想想,你实际上可以有一个安全配置:在 auth 入口处理程序中检查请求 url 如果有来自管理站点,你可以将它重定向到管理员登录,但它不是最好的解决方案,但应该可以。 非常感谢您的回复,我会考虑使用它:)

以上是关于Spring security - 指定顺序时多个httpsecurity不起作用[重复]的主要内容,如果未能解决你的问题,请参考以下文章

spring 多个切面

spring security

在 Spring Security Java Config 中创建多个 HTTP 部分

Spring Security 拦截 URL 究竟是如何工作的?

Spring Security 多个登录用户失败

Spring Security:如何在使用多个“http”元素时为给定 URL 授权用户?