2011-02-10 9 views

Respuesta

10

La forma más sencilla de hacer esto es usar un filtro en URL de sus peticiones AJAX.

En el siguiente ejemplo sólo estoy enviando 500 código de respuesta HTTP con un cuerpo de respuesta que indica el tiempo de espera de la sesión, pero se puede ajustar fácilmente el código de respuesta y el cuerpo a lo que es más adecuado para su caso ..

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

¿Dónde puedo añadir esto en el fichero de configuración de frijol? Intenté esto antes y tuve problemas con eso. No estoy seguro si lo configuré bien la primera vez. Esto parece estar en el camino correcto. –

+0

Suponiendo que ha Spring Security configurado correctamente, sólo tiene que añadir este filtro en la cadena de filtros de seguridad en su applicationContext-security.xml: definir el filtro como una _ _ y añadirlo a la cadena mediante _ _ –

+0

En su opinión, ¿cuál es el mejor lugar para inyectar este filtro con los otros filtros? El atributo de filtro personalizado tiene un antes/después de que contiene construido en filtros, http://static.springsource.org/spring-security/site/docs/3.0.x/reference/ns-config.html#ns-custom-filters . No quiero que se ejecute en todas las páginas a través de ajax, sino solo en páginas seguras como una sección de administrador. Definitivamente tengo que pegarle al filtro ahora, solo necesito asegurarme de que solo se ejecute en esas páginas seguras. ¡Después de eso, recibiste una respuesta ANSWER! –

3

Aquí hay un enfoque que creo que es bastante simple. Es una combinación de enfoques que he observado en este sitio. Escribí una publicación en el blog al respecto: http://yoyar.com/blog/2012/06/dealing-with-the-spring-security-ajax-session-timeout-problem/

La idea básica es usar un prefijo url api (es decir,/api/secured) como se sugiere arriba junto con un punto de entrada de autenticación. Es simple y funciona.

Aquí está el punto de entrada de autenticación:

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

Y esto es lo que pasa en su contexto XML de Spring:

<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

Puedo usar la misma solución por @ Matt en el back-end. Si está utilizando angularJs en el extremo frontal, agregue el interceptor siguiente en $ http angular para permitir que el navegador haga una redirección a la página de inicio de sesión.

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

});

Tenga en cuenta que por debajo de la línea que se necesita sólo si está utilizando AngularJS después de la versión 1.1.1 (AngularJS removidos cabecera "X-solicitada-Con" de esa versión en adelante)

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

En vista de que la totalidad de la presentes respuestas son unos pocos años ahora, voy a compartir mi solución que tengo actualmente trabajando en una aplicación de primavera de arranque RESTO:

@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()); 
    } 
} 

la premisa básica aquí es que puedo reemplazar el punto de entrada de autenticación que por defecto se emitir un redireccionamiento a mi página de inicio de sesión inexistente mi. Ahora responde enviando un 401. Spring también crea implícitamente un objeto JSON de respuesta de error estándar que devuelve también.

Cuestiones relacionadas