wake-up-neo.com

Ermitteln Sie das Sitzungszeitlimit in Ajax Request in Spring MVC

Ich kann anscheinend kein gutes Beispiel/keine gute Antwort dafür finden, wie einige Daten aus einer Ajax-Anfrage zurückgesendet werden, wenn eine Sitzung abgelaufen ist. Es sendet den HTML-Code der Anmeldeseite zurück und ich möchte entweder json oder einen Statuscode senden, den ich abfangen kann.

20
Mike Flynn

Die einfachste Möglichkeit hierfür ist die Verwendung eines Filters für URLs Ihrer AJAX -Anforderungen.

Im folgenden Beispiel sende ich nur den HTTP 500-Antwortcode mit einem Antworttext, der das Sitzungszeitlimit angibt. Sie können den Antwortcode und den Text jedoch problemlos auf den für Ihren Fall passenderen Wert festlegen.

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);
    }
}
11
Boris Kirzner

Hier ist ein Ansatz, den ich für ziemlich einfach halte. Es ist eine Kombination von Ansätzen, die ich auf dieser Website beobachtet habe. Ich habe einen Blogbeitrag darüber geschrieben: http://yoyar.com/blog/2012/06/das-bewältigen-der-spring-security-ajax-session-timeout-probleme/

Die Grundidee besteht darin, ein API-URL-Präfix (d. H./Api/secured) wie oben vorgeschlagen zusammen mit einem Authentifizierungseintrittspunkt zu verwenden. Es ist einfach und funktioniert.

Hier ist der Authentifizierungseinstiegspunkt:

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

Und hier ist, was in Ihrem Frühlingskontext xml geht:

<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>
3
Matt Friedman

Angesichts der Tatsache, dass alle Antworten der Gegenwart bereits einige Jahre alt sind, werde ich meine Lösung vorstellen, die ich derzeit in einer Spring Boot REST -Anwendung arbeite:

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

Die Grundvoraussetzung hierbei ist, dass ich den Authentifizierungseinstiegspunkt überschreibe, der standardmäßig eine Umleitung zu meiner nicht vorhandenen Anmeldeseite ausgab. Es antwortet jetzt mit dem Senden eines 401. Spring erstellt implizit auch ein JSON-Objekt für Standardfehlerantworten, das ebenfalls zurückgegeben wird.

1
pedorro

Ich benutze die gleiche Lösung von @Matt im Backend. Wenn Sie angleJs im Front-End verwenden, fügen Sie den folgenden Interceptor in angle $ http hinzu, damit der Browser tatsächlich zur Anmeldeseite umleitet.

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

});

Beachten Sie, dass die folgende Zeile nur benötigt wird, wenn Sie AngularJs nach Version 1.1.1 verwenden (AngularJS hat den Header "X-Requested-With" ab dieser Version entfernt).

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