2011-02-10 70 views

回答

10

這樣做的最簡單方法是對您的AJAX請求的URL使用過濾器。

在下面的例子中,我只是發送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); 
    } 
} 
+0

我在哪裏添加這個bean配置文件?我早些時候嘗試過,並且遇到了問題。我不確定第一次配置是否正確。這似乎是在正確的軌道上。 – 2011-02-11 16:05:41

3

以下是我認爲非常簡單的方法。這是我在這個網站上觀察到的方法的組合。我寫了一篇關於它的博客文章: http://yoyar.com/blog/2012/06/dealing-with-the-spring-security-ajax-session-timeout-problem/

基本思想是使用上面建議的api url前綴(即/ api/secured)以及身份驗證入口點。這很簡單,很有效。

這裏的身份驗證入口點:

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

這裏在你的Spring上下文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

我通過@馬特在後端使用相同的解決方案。如果您在前端使用angularJs,請在角度$ 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-要求,以」從該版本起)只需要

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

看到所有的目前的答案現在是幾歲,我會分享我的解決方案,我公司目前已在春季啓動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對象,它也會返回。