如何使用不显示 401 请求登录对话框的基本身份验证实现来实现 Grails spring 安全核心?

How to implement Grails spring security core with basic authentication implementation that doesn't show login dialog for 401 requests?

我有一个 Grails React 应用程序 spring 使用基本身份验证实现的安全核心。

我的 React 前端与 Grails 应用捆绑在一起。我对后端(我的 grails 应用程序)的所有请求,都是 post 请求。现在我只想要状态 401/403 但不是登录对话框提示无效请求或错误请求,就像在 POSTMAN 中一样。由于这个问题,我的整个系统都不正常,因为每个无效请求都会出现如图所示的登录对话框。

有没有办法避免这个登录对话框,让前端处理状态响应?

Grails 版本:3.3.5 Spring 安全核心版本:3.2.3

当使用基本身份验证时,触发登录对话框的东西 浏览器是存在一个WWW-Authenticate header 在 401 响应中。所以你的目标是删除它。

使用默认的 spring 安全设置,发送 headers 的原因是 BasicAuthenticationEntryPoint.

因为这也向用户显示了 realm,这里是基本身份验证中的挂钩 配置器来替换入口点(其中 BasicAuthenticationEntryPoint 是 如果未设置,则为默认值)。

下面是一个简单的 spring 安全性设置示例:

@Configuration
@EnableWebSecurity
class SecurityConfiguration extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests().anyRequest().authenticated()
                .and()
                .formLogin()
                    .disable()
                .httpBasic()
                    .authenticationEntryPoint(new BasicAuthenticationEntryPointWithoutWWWAuthenticate())
    }
}

// See org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint
class BasicAuthenticationEntryPointWithoutWWWAuthenticate implements AuthenticationEntryPoint {
    void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException {
        // XXX don't set the header, that triggers the browser to show the login form
        // response.addHeader("WWW-Authenticate", "Basic realm=\"" + realmName + "\"");
        response.sendError(HttpStatus.UNAUTHORIZED.value(), HttpStatus.UNAUTHORIZED.getReasonPhrase());
    }
}

我想要一种无需添加 spring-security-rest 即可使用现有实现解决此问题的快速简便方法。所以我按照@cfrick 的回答在我的回复中删除了 header“WWW-Authenticate”。 以下是我采取的步骤:

  1. 创建一个扩展 spring 的 GenericFilterBean 的自定义 spring 过滤器,按照此处的说明注册它:spring-security-grails-doc
  2. 创建自定义响应包装器以修改过滤器内的响应。
  3. 在响应包装器的 addHeader 方法中设置除 WWW-Authenticate.
  4. 之外的所有 header

这是我的过滤器代码:

class RemoveLoginPromptFilter extends GenericFilterBean{

    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
                         FilterChain chain) throws IOException, ServletException{
        HttpServletResponseWrapper wrapper = new HttpServletResponseWrapper((HttpServletResponse)response){
            @Override
            public void addHeader(String name, String value){
                if(!name.equalsIgnoreCase("www-authenticate")){
                    this.setHeader(name,value)
                }
            }
        }
        chain.doFilter(request,wrapper)
    }
}