如何在多 HttpSecurity 案例中返回 http 状态码而不是登录页面 [英] How to return http status code instead of login page in multi HttpSecurity case

查看:42
本文介绍了如何在多 HttpSecurity 案例中返回 http 状态码而不是登录页面的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 Spring Boot 应用程序,它通过 / 提供 HTML 页面服务,还通过 /api 提供 rest api.前者需要通过Login表单登录,后者需要HTTP基本认证,特此配置两个HttpSecurity部分如下:

I have a spring boot app which provides HTML page service via / and also rest api via /api. The former requires login via a Login form and the later requires HTTP basic auth, and hereby, I configure two HttpSecurity section as follows:

@Configuration
@Order(1)
public static class ApiSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter { 
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.antMatcher("/api/**")
            .cors().and().csrf().disable()
            .authorizeRequests().anyRequest().authenticated()
                .and()
                .httpBasic(Customizer.withDefaults());
    }
}

@Configuration
public static class FormLoginWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.antMatcher("/**")
                .cors().disable()
                .authorizeRequests()
                .antMatchers("/login", "/js/**", "/css/**").permitAll()
                .antMatchers("/**").hasRole("ADMIN")
                .and().formLogin().loginPage("/login").permitAll().defaultSuccessUrl("/index")
                .and().logout().invalidateHttpSession(true)
                .deleteCookies("JSESSIONID").logoutSuccessUrl("/login").permitAll();
    }
}

该配置在正常情况下完美运行.但是,如果在 rest api 客户端中提供了错误的凭据,则应用会返回带有 HTTP 状态代码 200 的登录页面的 HTML 代码,而不是带有 HTTP 状态代码 401 或 403 的异常 json 消息.

The configuration works perfectly in normal case. However, if wrong credentials are provides in rest api clients, an HTML code of login page with HTTP status code 200 returns from the app instead of an excepted json message with HTTP status code 401 or 403.

恐怕是因为 /api/** 的 url 模式都匹配 "/api/**""/**" ,因此,请求将同时通过 REST API 和 HTML 页面的过滤器链.最后,由于formLogin的顺序较低,案例中返回一个登录页面.

I'm afraid it is because the url pattern of /api/** both matches "/api/**" and "/**", and therefore, the request will pass both the filter chain for rest api and HTML page. Finally, because of the lower order of formLogin, a login page returns in the case.

那么,我怎样才能得到 REST API 客户端的异常结果呢?是否有唯一的解决方案来分隔不应该相互匹配的两个 url 模式?

So, How can I get the excepted result for rest api clients? Is there an only solution to separate the two url patterns which should not match each other?

添加 1:

我认为有三种情况会在安全过滤器链中引发异常:

I think there are three cases which will raise exceptions in the security filter chain:

  1. 未提供凭据;
  2. 提供的凭据有误;
  3. 提供了正确的凭据,但与所需的角色不匹配

案例的结果如下:

  1. 返回带有 json 错误消息的 HTTP 状态 401
  2. 返回 HTTP 状态 302 并尝试重定向到登录页面
  3. 返回带有 json 错误消息的 HTTP 状态 403

因此,似乎只有在提供错误凭据的情况下才会被路由到 /error 端点(正如 Eleftheria 在答案中所说的那样),1,3 和 2 之间的区别是异常类型 -- org.springframework.security.access.AccessDeniedException: 1 和 3 的访问被拒绝 org.springframework.security.authentication.BadCredentialsException:2 的凭据错误.

Therefore, it seems that only the case of wrong credentials provided will be routed to /error endpoint (as what Eleftheria said in the answer), and the difference between 1,3 and 2 is the exception type -- org.springframework.security.access.AccessDeniedException: Access is denied for 1 and 3; org.springframework.security.authentication.BadCredentialsException: Bad credentials for 2.

formLogin()的情况下,如果BadCredentialsException上升,会被路由到failure-url,但是如何配置httpbasic 案例中的 failure-url ?(HttpBasicConfigurer 中似乎没有这样的方法)

In the formLogin() case, if the BadCredentialsException rises, it will be routed to the failure-url, but how to configure the failure-url in the httpbasic case? (seems no such method in HttpBasicConfigurer)

推荐答案

发生这种情况是因为失败的身份验证引发异常并且/error"页面由您的第二个过滤器链保护.

This is happening because the failed authentication is throwing an exception and the "/error" page is secured by your second filter chain.

尝试允许所有请求/error";在您的第二个过滤器链中.

Try permitting all requests to "/error" in your second filter chain.

http.antMatcher("/**")
    .authorizeRequests()
        .antMatchers("/error").permitAll()
    // ....

请注意,请求只会被一个过滤器链处理,也就是它匹配的第一个过滤器链.

Note that the request will only be processed by one filter chain, and that is the first filter chain that it matches.

对/api/123"的请求仅由第一个过滤器链处理,但由于出现错误而调用了第二个过滤器链.

The request to "/api/123" is only processed by the first filter chain, however the second filter chain was invoked because there was an error.

这篇关于如何在多 HttpSecurity 案例中返回 http 状态码而不是登录页面的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆