2015-11-13 27 views
5

Sto lavorando con tutorial che spiega come scrivere semplice pagina singola applicazione utilizzando Primavera Boot, Sicurezza primavera e AngularJS: https://spring.io/guides/tutorials/spring-security-and-angular-js/sicurezza primavera con AngularJS - 404 al logout

Non posso logout attualmente connesso utente - quando ho eseguire la richiesta POST a "/ logout", ottengo "404 not found" - schermo da Google Chrome debugger:

enter image description here

Perché GET? Ho eseguito il POST. Perché "/ login? Logout", non "/ logout"? Ecco il codice che viene richiamato quando l'utente fa clic pulsante Esci: codice

$scope.logout = function() { 
      $http.post('logout', {}).success(function() { 
       $rootScope.authenticated = false; 
       $location.path("/"); 
      }).error(function(data) { 
       console.log("Logout failed") 
       $rootScope.authenticated = false; 
      }); 
     } 

Primavera:

@SpringBootApplication 
@RestController 
public class UiApplication { 

    @RequestMapping("/user") 
    public Principal user(Principal user) { 
     return user; 
    } 

    @RequestMapping("/resource") 
    public Map<String, Object> home() { 
     Map<String, Object> model = new HashMap<String, Object>(); 
     model.put("id", UUID.randomUUID().toString()); 
     model.put("content", "Hello World"); 
     return model; 
    } 

    public static void main(String[] args) { 
     SpringApplication.run(UiApplication.class, args); 
    } 

    @Configuration 
    @Order(SecurityProperties.ACCESS_OVERRIDE_ORDER) 
    protected static class SecurityConfiguration extends WebSecurityConfigurerAdapter { 
     @Override 
     protected void configure(HttpSecurity http) throws Exception { 
      http.httpBasic().and().authorizeRequests() 
        .antMatchers("/index.html", "/home.html", "/login.html", "/").permitAll().anyRequest() 
        .authenticated().and().csrf() 
        .csrfTokenRepository(csrfTokenRepository()).and() 
        .addFilterAfter(csrfHeaderFilter(), CsrfFilter.class); 
     } 

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

} 

intero codice AngularJS:

angular.module('hello', [ 'ngRoute' ]).config(function($routeProvider, $httpProvider) { 

    $routeProvider 
.when('/', {templateUrl : 'home.html', controller : 'home' }) 
.when('/login', { templateUrl : 'login.html', controller : 'navigation' }) 
.otherwise('/'); 

    $httpProvider.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest'; 

}).controller('navigation', 

     function($rootScope, $scope, $http, $location, $route) { 

      $scope.tab = function(route) { 
       return $route.current && route === $route.current.controller; 
      }; 

      var authenticate = function(credentials, callback) { 

       var headers = credentials ? { 
        authorization : "Basic " 
          + btoa(credentials.username + ":" 
            + credentials.password) 
       } : {}; 

       $http.get('user', { 
        headers : headers 
       }).success(function(data) { 
        if (data.name) { 
         $rootScope.authenticated = true; 
        } else { 
         $rootScope.authenticated = false; 
        } 
        callback && callback($rootScope.authenticated); 
       }).error(function() { 
        $rootScope.authenticated = false; 
        callback && callback(false); 
       }); 

      } 

      authenticate(); 
      $scope.credentials = {};    
      $scope.login = function() { 
       authenticate($scope.credentials, function(authenticated) { 
        if (authenticated) { 
         console.log("Login succeeded") 
         $location.path("/"); 
         $scope.error = false; 
         $rootScope.authenticated = true; 
        } else { 
         console.log("Login failed") 
         $location.path("/login"); 
         $scope.error = true; 
         $rootScope.authenticated = false; 
        } 
       })   
      }; 

      $scope.logout = function() { 
       $http.post('logout', {}).success(function() { 
        $rootScope.authenticated = false; 
        $location.path("/"); 
       }).error(function(data) { 
        console.log("Logout failed") 
        $rootScope.authenticated = false; 
       });   
      } 

     }).controller('home', function($scope, $http) { 
      $http.get('/resource/').success(function(data) {   
       $scope.greeting = data; }) }); 

Sono nuovo di primavera. Ecco l'intero codice da esercitazione - non funziona troppo: https://github.com/dsyer/spring-security-angular/tree/master/single

+0

Hai provato la mia risposta? –

+1

Nel caso in cui vuoi capire cosa è successo. Si ottiene GET invece di POST "perché in realtà ci sono 2 richieste per il logout. Il primo è il POST che hai fatto manualmente e che riceve una risposta con un codice di reindirizzamento alla risorsa "login? Logout". Quindi viene eseguita la richiesta GET per questa risorsa. Quando si "sostituisce" logoutSuccessHandler si esclude il reindirizzamento dalla richiesta di disconnessione (ad esempio, ci sarà una sola richiesta POST di "disconnessione" risorsa). –

risposta

6

In realtà quello che ti serve è solo per aggiungere un gestore di successo per il logout

@Component 
public class LogoutSuccess implements LogoutSuccessHandler { 

@Override 
public void onLogoutSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) 
     throws IOException, ServletException { 
    if (authentication != null && authentication.getDetails() != null) { 
     try { 
      httpServletRequest.getSession().invalidate(); 
      // you can add more codes here when the user successfully logs 
      // out, 
      // such as updating the database for last active. 
     } catch (Exception e) { 
      e.printStackTrace(); 
      e = null; 
     } 
    } 

    httpServletResponse.setStatus(HttpServletResponse.SC_OK); 

} 

} 

e aggiungere un gestore di successo alla sicurezza config

http.authorizeRequests().anyRequest().authenticated().and().logout().logoutSuccessHandler(logoutSuccess).deleteCookies("JSESSIONID").invalidateHttpSession(false).permitAll(); 
0

provare a cambiare $http.post('logout', {}) a questo $http.post('\logout')

Così sarà come questo:

$scope.logout = function() { 
    $http.post('\logout') 
     .success(function() { 
      // on success logic 
     }) 
     .error(function (data) { 
      // on errorlogic 
     }); 
} 
2

Nella versione più recente di primavera Boot v'è una classe chiamata HttpStatusReturningLogoutSuccessHandler che restituisce HTTP 200 per impostazione predefinita. La sua JavaDoc dice:

"Questo è utile in scenari REST-tipo in cui un redirect su un logout di successo non è desiderato".

per usarlo scrivere qualcosa di simile:

 //... 
     .formLogin() 
     .and() 
     .logout().logoutSuccessHandler(new HttpStatusReturningLogoutSuccessHandler()); 
+0

hai risolto il mio problema, grazie mille. –