Spring Boot + Spring Security:如何禁用基本身份验证表单

6

你好。

我正在使用Spring Boot自动配置应用程序的Spring安全性。我的目标是设置基本认证,使得在401错误时不会显示标准浏览器的基本认证表单。从谷歌上了解到,要实现此目的,需要将默认的“WWW-Authenticate”头更改为与“Basic xxxxx”不同的内容。

为了做到这一点,我声明了一个过滤器:

@Bean
@Order(Integer.MAX_VALUE)
public Filter customAuthFilter() {
    return new Filter() {

        @Override
        public void init(FilterConfig fc) throws ServletException {
        }

        @Override
        public void doFilter(ServletRequest sreq, ServletResponse sresp, FilterChain fc) throws IOException, ServletException {
            HttpServletRequest req = (HttpServletRequest) sreq;
            HttpServletResponse resp = (HttpServletResponse) sresp;

            fc.doFilter(req, resp);
            log.info("filter");
            log.info("status " + resp.getStatus());
            if(resp.getStatus() == 401) {
                resp.setHeader("WWW-Authenticate", "Client-driven");
            }
        }

        @Override
        public void destroy() {
        }
    };

从日志中我看到我的过滤器已经被应用程序成功识别并参与了响应处理(我可以看到来自doFilter的日志消息)。但是实际上,浏览器收到的响应仍然包含标准的“WWW-Authenticate”头。似乎有人覆盖了我的头,但我不知道确切是谁。

请问有人能给些建议吗?

3个回答

8

通过使用自定义的EntryPoint来解决了问题:

protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
            .antMatchers("/rest/**").authenticated()
            .and().httpBasic().authenticationEntryPoint(new AuthenticationEntryPoint() {
                @Override
                public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
                    String requestedBy = request.getHeader("X-Requested-By");
                    log.info("X-Requested-By: " + requestedBy);
                    if(requestedBy == null || requestedBy.isEmpty()) {
                        HttpServletResponse httpResponse = (HttpServletResponse) response;
                        httpResponse.addHeader("WWW-Authenticate", "Basic realm=Cascade Realm");
                        httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, authException.getMessage());
                    } else {
                        HttpServletResponse httpResponse = (HttpServletResponse) response;
                        httpResponse.addHeader("WWW-Authenticate", "Application driven");
                        httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, authException.getMessage());
                    }
                }
            });
}

2

Spring Security过滤器的优先级是最低的,可能在您的过滤器之前运行。您可以尝试降低它的顺序。处理401响应的传统方式是使用AuthenticationFailureHandler,但考虑到基本身份验证已经存在,我可以理解您这样做的原因。


谢谢您的回复。我已经尝试了您提到的传统方法 - 它确实很有用,但不是我要找的。似乎AuthenticationFailureHandler仅在身份验证失败时触发(用户在登录表单中提交无效凭据)。但我要找的是一种在向HTTP客户端回复之前透明地自定义某些响应标头的方法。在原始servlet环境中,我可以通过过滤器来实现这一点,但在Spring中,这种方法似乎工作方式不同... - skapral
过滤器就是过滤器。我唯一预见到的问题是,您可能需要屏蔽响应以防止在您的过滤器进行操作之前提交它。但是您已经说过您已经解决了这个问题,所以您只需要按正确的顺序进行操作。这很简单(只需更改顺序即可)。 - Dave Syer

0

只需在请求头中添加“X-Requested-With: XMLHttpRequest”(已在Spring Security 4.2.2.RELEASE中测试)。

有关详细信息,请查看HttpBasicConfigurer。

以下是我使用CURL进行的测试结果:

hanxideMacBook-Pro:~ hanxi$ curl -u "13980547109:xxx" -v -d "" -H "X-Requested-With: XMLHttpRequest" http://sales.huoxingy.com/api/v1/sales/login
*   Trying 101.37.135.20...
* TCP_NODELAY set
* Connected to sales.huoxingy.com (101.37.135.20) port 80 (#0)
* Server auth using Basic with user '13980547109'
> POST /api/v1/sales/login HTTP/1.1
> Host: sales.huoxingy.com
> Authorization: Basic MTM5ODA1NDcxMDk6MTIzNDU2
> User-Agent: curl/7.54.0
> Accept: */*
> X-Requested-With: XMLHttpRequest
> Content-Length: 0
> Content-Type: application/x-www-form-urlencoded
> 
< HTTP/1.1 200 
< Server: nginx/1.12.1
< Date: Thu, 21 Sep 2017 01:43:13 GMT
< Content-Length: 0
< X-Content-Type-Options: nosniff
< X-XSS-Protection: 1
< Cache-Control: no-cache, no-store, max-age=0, must-revalidate
< Pragma: no-cache
< Expires: 0
< X-Frame-Options: DENY
< X-XSS-Protection: ; mode=block
< x-auth-token: 2f595113-cdba-4394-8ca0-bcd72239bea5
< Set-Cookie: CONTAINERID=efc390abdb189a10c55e0672b07cfe1c7d665be4db9ad40e122475e5cdff605d; path=/

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接