登录失败后,Spring Boot 安全性显示 Http-Basic-Auth 弹出窗口 [英] Spring Boot security shows Http-Basic-Auth popup after failed login

查看:70
本文介绍了登录失败后,Spring Boot 安全性显示 Http-Basic-Auth 弹出窗口的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在为一个学校项目、Spring Boot 后端和 AngularJS 前端创建一个简单的应用程序,但有一个我似乎无法解决的安全问题.

I'm currently creating a simple app for a school project, Spring Boot backend and AngularJS frontend, but have a problem with security that I can't seem to solve.

登录工作正常,但是当我输入错误的密码时,会出现默认登录弹出窗口,这有点烦人.我已经尝试了注释BasicWebSecurity"并将 httpBassic 置于禁用状态,但没有结果(意思是,登录过程不再起作用).

Logging in works perfectly, but when I enter a wrong password the default login popup shows up, which is kind of annoying. I've tried the annotation 'BasicWebSecurity' and putting httpBassic on disabled, but with no result (meaning, that the login procedure doesn't work at all anymore).

我的安全类:

package be.italent.security;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.security.SecurityProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.csrf.CsrfFilter;
import org.springframework.security.web.csrf.CsrfToken;
import org.springframework.security.web.csrf.CsrfTokenRepository;
import org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.util.WebUtils;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService);
    }

    @Override
    public void configure(WebSecurity web){
        web.ignoring()
        .antMatchers("/scripts/**/*.{js,html}")
        .antMatchers("/views/about.html")
        .antMatchers("/views/detail.html")
        .antMatchers("/views/home.html")
        .antMatchers("/views/login.html")
        .antMatchers("/bower_components/**")
        .antMatchers("/resources/*.json");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.httpBasic()
                    .and()
                .authorizeRequests()
                .antMatchers("/user", "/index.html", "/", "/projects/listHome", "/projects/{id}", "/categories", "/login").permitAll().anyRequest()
                .authenticated()
                    .and()
                .csrf().csrfTokenRepository(csrfTokenRepository())
                    .and()
                .addFilterAfter(csrfHeaderFilter(), CsrfFilter.class).formLogin();
    }

    private Filter csrfHeaderFilter() {
        return new OncePerRequestFilter() {
            @Override
            protected void doFilterInternal(HttpServletRequest request,
                                            HttpServletResponse response, FilterChain filterChain)
                    throws ServletException, IOException {
                CsrfToken csrf = (CsrfToken) request.getAttribute(CsrfToken.class
                        .getName());
                if (csrf != null) {
                    Cookie cookie = WebUtils.getCookie(request, "XSRF-TOKEN");
                    String token = csrf.getToken();
                    if (cookie == null || token != null
                            && !token.equals(cookie.getValue())) {
                        cookie = new Cookie("XSRF-TOKEN", token);
                        cookie.setPath("/");
                        response.addCookie(cookie);
                    }
                }
                filterChain.doFilter(request, response);
            }
        };
    }

    private CsrfTokenRepository csrfTokenRepository() {
        HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
        repository.setHeaderName("X-XSRF-TOKEN");
        return repository;
    }
}

有人知道如何在不破坏其余部分的情况下防止显示此弹出窗口吗?

Does anybody have an idea on how to prevent this popup from showing without breaking the rest?

解决方案

将此添加到我的 Angular 配置中:

Added this to my Angular config:

myAngularApp.config(['$httpProvider',
  function ($httpProvider) {
    $httpProvider.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
  }
]);

推荐答案

让我们从你的问题开始

如果您的 Spring Boot 应用程序的响应包含以下标头,则它不是Spring Boot 安全弹出窗口",而是显示的浏览器弹出窗口:

It is not a "Spring Boot security popup" its a browser popup that shows up, if the response of your Spring Boot app contains the following header:

WWW-Authenticate: Basic

在您的安全配置中,会出现 .formLogin().这不应该是必需的.虽然您想通过 AngularJS 应用程序中的表单进行身份验证,但您的前端是一个独立的 javascript 客户端,它应该使用 httpBasic 而不是表单登录.

In your security configuration a .formLogin() shows up. This should not be required. Though you want to authenticate through a form in your AngularJS application, your frontend is an independent javascript client, which should use httpBasic instead of form login.

您的安全配置如何

我删除了 .formLogin() :

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
            .httpBasic()
                .and()
            .authorizeRequests()
            .antMatchers("/user", "/index.html", "/", "/projects/listHome", "/projects/{id}", "/categories", "/login").permitAll().anyRequest()
            .authenticated()
                .and()
            .csrf().csrfTokenRepository(csrfTokenRepository())
                .and()
            .addFilterAfter(csrfHeaderFilter(), CsrfFilter.class);
}

如何处理浏览器弹窗

如前所述,如果您的 Spring Boot 应用程序的响应包含标头 WWW-Authenticate: Basic,则会显示弹出窗口.不应为 Spring Boot 应用程序中的所有请求禁用此功能,因为它允许您非常轻松地在浏览器中浏览 API.

As previously mentioned the popup shows up if the response of your Spring Boot app contains the header WWW-Authenticate: Basic. This should not be disabled for all requests in your Spring Boot app, since it allows you to explore the api in your browser very easily.

Spring Security 有一个默认配置,允许您在每个请求中告诉 Spring Boot 应用程序不要在响应中添加此标头.这是通过为您的请求设置以下标头来完成的:

Spring Security has a default configuration that allows you to tell the Spring Boot app within each request not to add this header in the response. This is done by setting the following header to your request:

X-Requested-With: XMLHttpRequest

如何将此标头添加到您的 AngularJS 应用发出的每个请求

您可以像这样在应用程序配置中添加默认标题:

You can just add a default header in the app config like that:

yourAngularApp.config(['$httpProvider',
  function ($httpProvider) {
    $httpProvider.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
  }
]);

后端现在将以 401 响应进行响应,您必须通过 Angular 应用程序(例如通过拦截器)处理该响应.

The backend will now respond with a 401-response that you have to handle by your angular app (by an interceptor for example).

如果您需要一个如何执行此操作的示例,您可以查看我的购物清单应用.它使用 spring boot 和 angular js 完成.

If you need an example how to do this you could have a look at my shopping list app. Its done with spring boot and angular js.

这篇关于登录失败后,Spring Boot 安全性显示 Http-Basic-Auth 弹出窗口的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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