5

Ich erstelle derzeit eine einfache App für ein Schulprojekt, Spring Boot Backend und AngularJS Frontend, aber ein Sicherheitsproblem, das ich nicht lösen kann .Spring Boot Sicherheit zeigt Http-Basic-Auth Popup nach fehlgeschlagener Anmeldung

Anmeldung funktioniert einwandfrei, aber wenn ich ein falsches Passwort eingib, erscheint das Standard-Login-Popup, was irgendwie nervig ist. Ich habe die Annotation 'BasicWebSecurity' ausprobiert und httpBassic auf deaktiviert gesetzt, aber ohne Ergebnis (was bedeutet, dass die Login-Prozedur überhaupt nicht mehr funktioniert).

Meine Sicherheitsklasse:

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; 
    } 
} 

Hat jemand eine Idee haben, wie aus zeigt dieses Popup zu verhindern, ohne den Rest zu brechen?

Lösung

hinzugefügt dies meine Angular config:

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

Ihre Sicherheitskonfiguration sieht ein bisschen verwirrend aus. Zuerst aktivierst du httpBasic. dann möchten Sie Formular Login verwenden und dann möchten Sie httpBasic deaktivieren. Für mich ist nicht klar, was Sie schützen möchten und auf welche Weise. Der csrfHeaderFilter sieht so aus als hättest du ein angularJS Frontend. Ist das der Fall? –

+0

Mist, ich habe eine falsche Kopie/Paste gemacht. Das letzte httpBasic(). Disable() soll nicht da sein. Mein Fehler! Es ist in der Tat ein angularJS-Frontend. – Daemun

+0

Ok. Eine Antwort wird in ein paar Minuten zur Verfügung gestellt. Hoffentlich wollen Sie das erreichen. Lass es mich nicht einfach in den Kommentaren wissen. –

Antwort

13

Lassen Sie sich mit Ihrem Problem beginnt

Es ist kein "Spring-Boot-Sicherheits-Popup" its a Popup-Browser Dies wird angezeigt, wenn die Antwort Ihrer Spring Boot-App die folgende Kopfzeile enthält:

WWW-Authenticate: Basic 

In Ihrer Sicherheitskonfiguration erscheint eine .formLogin(). Dies sollte nicht erforderlich sein. Obwohl Sie sich über ein Formular in Ihrer AngularJS-Anwendung authentifizieren möchten, ist Ihr Frontend ein unabhängiger Javascript-Client, der httpBasic anstelle der Formularanmeldung verwenden sollte.

Wie Sie Ihre Sicherheit Config wie

aussehen könnte ich entfernt die .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); 
} 

Wie mit dem Browser Popup

Wie bereits das Popup erwähnt befassen zeigt, wenn Die Antwort Ihrer Spring Boot App enthält die Kopfzeile WWW-Authenticate: Basic. Dies sollte nicht für alle Anfragen in Ihrer Spring Boot-App deaktiviert werden, da Sie damit sehr einfach die API in Ihrem Browser erkunden können.

Spring Security verfügt über eine Standardkonfiguration, mit der Sie der Spring Boot-App innerhalb jeder Anforderung mitteilen können, dass diese Kopfzeile nicht in die Antwort eingefügt werden soll. Dies geschieht, indem Sie den folgenden Header auf Ihre Anfrage Einstellung:

X-Requested-With: XMLHttpRequest 

Wie diesen Header von Ihrem AngularJS App

Sie jede Anfrage kann ein Standard-Header in der App Config fügen Sie einfach gemacht hinzuzufügen wie dass:

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

Das Backend wird nun mit einer 401-Antwort reagiert, dass Sie durch Ihre Winkel App (durch Abfangjäger zum Beispiel) zu behandeln haben.

Wenn Sie ein Beispiel benötigen, wie Sie das tun, können Sie sich meine shopping list app ansehen. Es ist mit Spring Boot und eckigen js getan.