2011-02-10 24 views

Odpowiedz

10

Najprostszym sposobem na to jest użycie filtru dla adresów URL żądań AJAX.

W przykładzie poniżej Ja tylko wysyłanie HTTP 500 kod odpowiedzi z ciałem odpowiedzi wskazuje limit czasu sesji, ale można łatwo ustawić kod odpowiedzi i ciało do tego, co jest bardziej korzystne dla sprawy ..

package com.myapp.security.authentication; 

import org.springframework.web.filter.GenericFilterBean; 

import javax.servlet.FilterChain; 
import javax.servlet.ServletException; 
import javax.servlet.ServletRequest; 
import javax.servlet.ServletResponse; 
import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpServletResponse; 
import java.io.IOException; 

public class ExpiredSessionFilter extends GenericFilterBean { 

    static final String FILTER_APPLIED = "__spring_security_expired_session_filter_applied"; 

    @Override 
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { 

     HttpServletRequest request = (HttpServletRequest) req; 
     HttpServletResponse response = (HttpServletResponse) res; 

     if (request.getAttribute(FILTER_APPLIED) != null) { 
      chain.doFilter(request, response); 
      return; 
     } 

     request.setAttribute(FILTER_APPLIED, Boolean.TRUE); 
     if (request.getRequestedSessionId() != null && !request.isRequestedSessionIdValid()) {    
      response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "SESSION_TIMED_OUT"); 
      return; 
     } 

     chain.doFilter(request, response); 
    } 
} 
+0

Gdzie mogę to dodać w pliku konfiguracyjnym komponentu bean? Próbowałem wcześniej i miałem z tym problemy. Nie jestem pewien, czy skonfigurowałem go poprawnie za pierwszym razem. Wydaje się, że jest na dobrej drodze. –

+0

Zakładając, że Spring Security jest poprawnie skonfigurowany, wystarczy dodać ten filtr do łańcucha filtrów bezpieczeństwa w pliku applicationContext-security.xml: zdefiniować filtr jako _ _ i dodać go do łańcucha za pomocą _ _ –

+0

Twoim zdaniem, co jest najlepszym miejscem, aby wprowadzić ten filtr z innymi filtrami. Niestandardowy atrybut filtru ma wartość przed/po zawierającą wbudowane filtry: http://static.springsource.org/spring-security/site/docs/3.0.x/reference/ns-config.html#ns-custom-filters . Nie chcę, aby działała na każdej stronie przez ajax, ale tylko na stronach zabezpieczonych jak sekcja administratora. Zdecydowanie mam teraz filtr, ale muszę się upewnić, że działa tylko na zabezpieczonych stronach. Potem otrzymasz ode mnie ODPOWIEDŹ! –

3

Oto podejście, które moim zdaniem jest dość proste. Jest to połączenie podejść, które zaobserwowałem na tej stronie. Napisałem o tym wpis na blogu: http://yoyar.com/blog/2012/06/dealing-with-the-spring-security-ajax-session-timeout-problem/

Podstawową ideą jest użycie przedrostka adresu URL api (tj./Api/secure), jak zasugerowano powyżej, wraz z punktem wejścia do uwierzytelniania. To proste i działa.

Oto punkt wejścia uwierzytelniania:

package com.yoyar.yaya.config; 

import org.springframework.security.core.AuthenticationException; 
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint; 

import javax.servlet.ServletException; 
import javax.servlet.http.*; 
import java.io.IOException; 

public class AjaxAwareAuthenticationEntryPoint 
      extends LoginUrlAuthenticationEntryPoint { 

    public AjaxAwareAuthenticationEntryPoint(String loginUrl) { 
     super(loginUrl); 
    } 

    @Override 
    public void commence(
     HttpServletRequest request, 
     HttpServletResponse response, 
     AuthenticationException authException) 
      throws IOException, ServletException { 

     boolean isAjax 
      = request.getRequestURI().startsWith("/api/secured"); 

     if (isAjax) { 
      response.sendError(403, "Forbidden"); 
     } else { 
      super.commence(request, response, authException); 
     } 
    } 
} 

A oto, co się dzieje w twojej wiosennej kontekstowego xml:

<bean id="authenticationEntryPoint" 
    class="com.yoyar.yaya.config.AjaxAwareAuthenticationEntryPoint"> 
    <constructor-arg name="loginUrl" value="/login"/> 
</bean> 

<security:http auto-config="true" 
    use-expressions="true" 
    entry-point-ref="authenticationEntryPoint"> 
    <security:intercept-url pattern="/api/secured/**" access="hasRole('ROLE_USER')"/> 
    <security:intercept-url pattern="/login" access="permitAll"/> 
    <security:intercept-url pattern="/logout" access="permitAll"/> 
    <security:intercept-url pattern="/denied" access="hasRole('ROLE_USER')"/> 
    <security:intercept-url pattern="/" access="permitAll"/> 
    <security:form-login login-page="/login" 
         authentication-failure-url="/loginfailed" 
         default-target-url="/login/success"/> 
    <security:access-denied-handler error-page="/denied"/> 
    <security:logout invalidate-session="true" 
        logout-success-url="/logout/success" 
        logout-url="/logout"/> 
</security:http> 
1

używam tego samego rozwiązania przez @Matt w backend. Jeśli używasz angularJs na pierwszym końcu, dodaj poniżej przechwytywacza w kanciastym $ http, aby przeglądarka faktycznie wykonała przekierowanie do strony logowania.

var HttpInterceptorModule = angular.module('httpInterceptor', []) 
.config(function ($httpProvider) { 
    $httpProvider.interceptors.push('myInterceptor'); 
    $httpProvider.defaults.headers.common["X-Requested-With"] = 'XMLHttpRequest'; 
}) 
.factory('myInterceptor', function ($q) { 
return { 
    'responseError': function(rejection) { 
     // do something on error 
     if(rejection.status == 403 || rejection.status == 401) window.location = "login"; 
     return $q.reject(rejection); 
    } 
    }; 

});

Zauważ, że poniżej linii jest potrzebne tylko wtedy, gdy używasz angularjs po Wersja 1.1.1 (angularjs usunięte nagłówka „X-Requested-With” od tej wersji naprzód)

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

Widząc, jak wszystkie z obecne są odpowiedzi na kilka lat teraz, będę dzielić moje rozwiązanie, które obecnie mam pracę w aplikacji Wiosna Boot rekreacyjne:

@Configuration 
@EnableWebSecurity 
public class UISecurityConfig extends WebSecurityConfigurerAdapter { 

    @Override 
    protected void configure(HttpSecurity http) throws Exception { 
     ... 
     http.exceptionHandling.authenticationEntryPoint(authenticationEntryPoint()); 
     ... 
    } 

    private AuthenticationEntryPoint authenticationEntryPoint() { 
     // As a REST service there is no 'authentication entry point' like MVC which can redirect to a login page 
     // Instead just reply with 401 - Unauthorized 
     return (request, response, authException) -> response.sendError(HttpServletResponse.SC_UNAUTHORIZED, authException.getMessage()); 
    } 
} 

podstawowym założeniem jest to, że mogę zastąpić punkt wejścia uwierzytelniania, które domyślnie było wydawanie przekierowania do mojej nieistniejącej strony logowania mi. Teraz odpowiada, wysyłając 401. Spring również niejawnie tworzy standardowy obiekt JSON odpowiedzi na błąd, który również zwraca.

Powiązane problemy