Определите время ожидания сеанса в Ajax-запросе в Spring MVC - PullRequest
20 голосов
/ 11 февраля 2011

Я не вижу хорошего примера / ответа о том, как отправить некоторые данные из запроса ajax, когда время сеанса истекло. Он отправляет обратно страницу входа в HTML, и я хочу отправить json или код состояния, который я могу перехватить.

Ответы [ 4 ]

11 голосов
/ 11 февраля 2011

Самый простой способ сделать это - использовать фильтр URL-адресов ваших запросов AJAX.

В приведенном ниже примере я просто отправляю код ответа HTTP 500 с телом ответа, указывающим время ожидания сеанса, но вы можете легко установить для кода ответа и тела значение более подходящее для вашего случая.

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);
    }
}
3 голосов
/ 19 июня 2012

Вот подход, который я считаю довольно простым.Это комбинация подходов, которые я наблюдал на этом сайте.Я написал сообщение в блоге об этом: http://yoyar.com/blog/2012/06/dealing-with-the-spring-security-ajax-session-timeout-problem/

Основная идея - использовать префикс api url (т.е. / api / secure), как предложено выше, вместе с точкой входа для аутентификации.Это просто и работает.

Вот точка входа аутентификации:

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

А вот что происходит в вашем весеннем контексте 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 голос
/ 10 декабря 2015

Поскольку всем настоящим ответам уже несколько лет, я поделюсь своим решением, которое в настоящее время используется в приложении Spring Boot REST:

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

Основная предпосылка здесь заключается в том, чтоЯ переопределяю точку входа аутентификации, которая по умолчанию выдала перенаправление на мою несуществующую страницу входа.Теперь он отправляет 401. Spring также неявно создает стандартный JSON-объект ответа на ошибку, который он также возвращает.

1 голос
/ 13 ноября 2013

Я использую то же решение @Matt в бэкэнде.Если вы используете angularJ на внешнем интерфейсе, добавьте перехватчик ниже в angular $ http, чтобы позволить браузеру фактически перенаправить на страницу входа.

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

});

Обратите внимание, что ниже строкитребуется только в том случае, если вы используете AngularJs после версии 1.1.1 (angularJS удалил заголовок "X-Requested-With" с этой версии и далее)

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