1. 程式人生 > >關於shiro使用時候,cookie被禁用的處理

關於shiro使用時候,cookie被禁用的處理

        在shiro使用過程中,保持客戶端的狀態是通過兩種方式關聯。一種方式是通過cookie返回,一種是通過重定向回寫url。但是重定向解決不了ajax請求。 如果客戶端禁用了cookie,會導致shiro無法獲得seesion儲存的認證,授權資訊。導致shiro無法使用。

        解決思路:在客戶端與服務端進行互動之前,普通請求通過重定向會寫url帶上會話資訊。ajax請求通過寫訊息頭形式,返回特定錯誤讓客戶端獲取相應頭得到seesionId。如果請求後臺沒有用到seesion,可以不用先獲取會話,否則所有的請求都必須先獲得會話。

客戶端獲取到訊息頭後,儲存會話id,每次請求在通過header帶上會話資訊(一定要帶上,特別是重定向的請求,必須從url獲取到會話id)。

        也可以不需要先獲取認證資訊,如果使用cookie形式的方式,是不需要先獲的會話。服務端使用了會話,自動寫cookie到客戶端。但是禁用了cookie,服務端產生了會話,相應得到了正確處理,然後在響應頭裡寫訊息頭,客戶端每次請求都從訊息頭裡獲取會話id,當然這樣實現也是可以的。

程式碼如下,相容cookie模式。

public class OssWebSessionManager extends DefaultWebSessionManager implements WebSessionManager {
  
	private static final Logger log = LoggerFactory.getLogger(OssWebSessionManager.class);
	
	private boolean sessionIdHeaderEnabled;
	 
	public static final String HEADER_SESSION_NAME = "X-AUTH-SESSION";
	
	public static final String HEADER_SESSION_ID_SOURCE = "header";
   
     public OssWebSessionManager() {
         super();
         //重定向無法手動帶上header
         super.setSessionIdUrlRewritingEnabled(true);
         sessionIdHeaderEnabled=true;
     }
     
     @Override
     protected Session createExposedSession(Session session,SessionContext context) {
    	 return super.createExposedSession(session, context);
     }
     
     @Override
     protected Session createExposedSession(Session session, SessionKey key) {
    	 return super.createExposedSession(session, key);
     }
      
     @Override
     protected void onStart(Session session, SessionContext context) {
         super.onStart(session, context);

         HttpServletRequest request = WebUtils.getHttpRequest(context);
         HttpServletResponse response = WebUtils.getHttpResponse(context);
         //用header儲存會話sessionId
         if (sessionIdHeaderEnabled) {
             Serializable sessionId = session.getId();
             storeSessionId(sessionId, request, response);
         } 
     }
     
     @Override
     public Serializable getSessionId(SessionKey key) {
         Serializable id = super.getSessionId(key);
         if(null != id){
        	 return id;
         }
         if (WebUtils.isWeb(key)) {
             ServletRequest request = WebUtils.getRequest(key);
             ServletResponse response = WebUtils.getResponse(key);
             id = getHeaderSessionId(request, response);
         }
         return id;
     }

   
     protected Serializable getHeaderSessionId(ServletRequest request, ServletResponse response) {
    	 String id=getHeaderSessionId((HttpServletRequest)request);
    	 if (id != null) {
             request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE,OssWebSessionManager.HEADER_SESSION_ID_SOURCE);
         }
    	 if (id != null) {
             request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, id);
             request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE);
         }
         request.setAttribute(ShiroHttpServletRequest.SESSION_ID_URL_REWRITING_ENABLED, isSessionIdUrlRewritingEnabled());
         return id;
     }
     
     @Override
     protected void onExpiration(Session s, ExpiredSessionException ese, SessionKey key) {
         super.onInvalidation(s, ese, key);
         onInvalidation(key);
     }
	
     @Override
     protected void onInvalidation(Session session, InvalidSessionException ise, SessionKey key) {
         super.onInvalidation(session, ise, key);
         onInvalidation(key);
     }
     
     @Override
     protected void onStop(Session session, SessionKey key) {
         super.onStop(session, key);
         onInvalidation(key);
     }
     
     @Override
     public boolean isServletContainerSessions() {
         return false;
     }

     private void storeSessionId(Serializable currentId, HttpServletRequest request, HttpServletResponse response) {
         if (currentId == null) {
             String msg = "sessionId cannot be null when persisting for subsequent requests.";
             throw new IllegalArgumentException(msg);
         }
         response.setHeader(OssWebSessionManager.HEADER_SESSION_NAME,currentId.toString());
         log.trace("Set session ID  header for session with id {}", currentId.toString());
     }
     
     /**
      * 獲取請求的token
      */
     private String getHeaderSessionId(HttpServletRequest httpRequest){
    	 String sessionId=null;
    	 //從header中獲取session
    	 sessionId = httpRequest.getHeader(OssWebSessionManager.HEADER_SESSION_NAME);
         //如果header中不存在token,則從引數中獲取token
         if(!StringUtils.hasText(sessionId)){
        	 sessionId = httpRequest.getParameter(OssWebSessionManager.HEADER_SESSION_NAME);
         }
         return sessionId;
     }
     
     private void onInvalidation(SessionKey key) {
    	 if (WebUtils.isWeb(key)) {
        	 ServletResponse response = WebUtils.getResponse(key);
        	 if(null != response){
        		 ((HttpServletResponse)response).addHeader(OssWebSessionManager.HEADER_SESSION_NAME, "");
        	 }
         }
     }

	public boolean isSessionIdHeaderEnabled() {
		return sessionIdHeaderEnabled;
	}

	public void setSessionIdHeaderEnabled(boolean sessionIdHeaderEnabled) {
		this.sessionIdHeaderEnabled = sessionIdHeaderEnabled;
	}
}
需要認證的請求
public class OssAuthenticationFilter extends AuthenticationFilter {

	private static final Logger log = LoggerFactory.getLogger(OssAuthenticationFilter.class);

		
	@Override
	protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
		Subject subject=SecurityUtils.getSubject();
		if(isRelogin( request,  response, subject)){
			return false; 
		}
		return subject.isAuthenticated();
	}
	
	protected  boolean isRelogin(ServletRequest request, ServletResponse response,Subject subject) throws IOException{
		Session session=subject.getSession(false);
		if(null == session){
			 if(isAjax(request)){
					//無法手動帶上sessionId,從訊息頭獲取sessionId
				    session=subject.getSession();
	            	response.getWriter().write(JSON.toJSONString(ResultBuilder.genExpResult(new AppBizException(AppExcCodesEnum.SESSION_TIMEOUT))));
	            }else{
	            	request.setAttribute(ShiroHttpServletRequest.SESSION_ID_URL_REWRITING_ENABLED, true);
	                this.saveRequestAndRedirectToLogin(request, response);
	            }
			 return true;
		}
		return false;
	}
	
	protected  boolean isAjax(ServletRequest request){
        String header = ((HttpServletRequest) request).getHeader("X-Requested-With");
        if("XMLHttpRequest".equalsIgnoreCase(header)){
            return Boolean.TRUE;
        }
        return Boolean.FALSE;
    }

}


不需要認證,只需要有會話的請求
public class OssNoAuthenticationFilter extends OssAuthenticationFilter {

	private static final Logger log = LoggerFactory.getLogger(OssNoAuthenticationFilter.class);
	
	@Override
	protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
		Subject subject=SecurityUtils.getSubject();
		if(isRelogin( request,  response, subject)){
			return false; 
		}
		return true;
	}
}


shiro過濾器配置
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">  
	    <!-- Shiro的核心安全介面,這個屬性是必須的 -->  
	    <property name="securityManager" ref="securityManager"/>  
	    <!-- 要求登入時的連結(可根據專案的URL進行替換),非必須的屬性,預設會自動尋找Web工程根目錄apos.htmlhtml"頁面 -->
	    <property name="loginUrl" value="${shiro.loginUrl}"/>
	    <!-- 登入成功後要跳轉的連線 -->  
	    <property name="successUrl" value="/sys/manager/index"/>
	    <!-- 使用者訪問未對其授權的資源時,所顯示的連線 -->  
	    <!-- 若想更明顯的測試此屬性可以修改它的值,如unauthor.jsp-->  
	    <property name="unauthorizedUrl" value="/sys/manager/login"/>  
	    <property name="filters">
			<map>
			<entry key="authc">
			    <bean class="tc.oss.web.shiro.OssAuthenticationFilter" />
			</entry>
			<entry key="noAuthc">
                <bean class="tc.oss.web.shiro.OssNoAuthenticationFilter" />
            </entry>
			<entry key="validCode">
                <bean class="tc.oss.web.shiro.ValidCodeAuthenticationFilter">
                     <property name="validCodeUrl" value="/sys/manager/validCode" />
                </bean>
            </entry>
			<!-- <entry key="ssl">
			    <ref bean="sslFilter" />
			</entry> -->
			</map>
		</property>
	    <property name="filterChainDefinitions">  
	        <value>
	        	/statics/**=anon
				/js/**=anon
	        	/page/**=anon
	        	/sys/manager/login=noAuthc
	        	/sys/manager/captcha=noAuthc
	        	/favicon.ico=anon
	        	/sys/manager/validCode=authc
	        	/sys/manager/commitCode=authc
	        	/**=authc
	        </value>
	    </property>
	</bean>

這樣客戶端禁用cookie也能用了,請求必須帶上header。從url或者響應中獲取
url回撥的
 function refreshCode(){
	  var sid=window.location.href.split(";")[1].split("=")[1];
	  $.ajax({
	         type: "GET",
	         url: "${contextPath}/sys/manager/captcha?t=" + $.now(),
	         beforeSend: function (XMLHttpRequest) {
	        	 var sessionid = "X-AUTH-SESSION";
	        	 XMLHttpRequest.setRequestHeader(sessionid, sid);
	         },
	         success: function(r){
	        	 $("#captchaImg").attr("src",r);
	         }
	     });
  }
ajax非同步請求的沒測試了,應該是沒問題的了


相關推薦

關於shiro使用時候cookie禁用處理

        在shiro使用過程中,保持客戶端的狀態是通過兩種方式關聯。一種方式是通過cookie返回,一種是通過重定向回寫url。但是重定向解決不了ajax請求。 如果客戶端禁用了cookie,會導致shiro無法獲得seesion儲存的認證,授權資訊。導致shir

Cookie與Session 的區別cookie禁用session是否還可以使用?

什麼是Cookie,什麼是cookie會話機制?cookie與session的區別(這裡寫自定義目錄標題) cookie的內容主要包括:名字,值,過期時間,路徑和域。路徑與域一起構成cookie的作用範圍。 若不設定過期時間,則表示這個cookie的生命期為瀏覽器會話期間,關閉瀏

控制元件system.windows.forms.Label在設計器中引發了一個未經處理的異常禁用

問題出現在MDI窗體中,用PictureBox作為MDI窗體背景圖片(更改MDI窗體背景屬性執行效果不是很理想)問題出現了,畫一個控制元件它會報錯,提示 給控制元件設定一下父容器。 程式碼:labe

使用URL重寫解決 Cookie禁用導致的使用者Session遺失

大家都知道使用者和web應用互動,通過Session的方式。 那麼客戶端是如何在伺服器上一下子找到屬於自己的那個Session呢? 一般情況下,客戶端是通過cookie 的方式找到伺服器上的Session的。 可以開啟自己的瀏覽器找到SESSIONID 這個cookie。裡

Safari無痕模式下storage禁用問題

前言 Safari開啟無痕模式後,localStorage和sessionStorage為空,對其進行set操作也會報錯,也就是說這種情況下,storage是被禁止使用了。接下來說一下解決方法。 解決方案 我們專案框架上的解決方法是對storage進行一層封裝,遇到這種開啟無痕模式的情況,會定義一個wi

RichTextBox 新增控制元件禁用如何處理 button

 WPF中RichTextBox的確非常的強大, 但讓人很鬱悶的是:新增到其中的控制元件總是被禁用的(IsEnabled始終為false)   參考以下程式碼: <Window  xmlns="http://schemas.microsoft.com/winfx/200

jmeter手寫腳本使用正則獲取cookie禁用cookies管理器)

coo inf 手動 全局 其他 去掉 bugfree 因此 頭信息 註:這裏以bugfree為例 1.bugfree登錄時會有重定向,這會導致每個URL都會有。因此要手動獲取cookie的時候,需要去掉重定向勾選 正則獲取動態PHPsession 獲取到值後,放到信

通過powershell查詢OU中禁用的AD賬號並刪除他們的所屬組

port enable memberof sele lse mov rop acc identity 這個需求可以通過兩個方向來實現1、找到禁用的賬號,刪除除domain users外的所有組,腳本內容如下 #導入AD模塊import-module ActiveDirect

解決---MISCONF Redis配置為儲存RDB快照但目前無法在磁碟上存留。可能修改資料集的命令禁用。請檢查Redis日誌瞭解有關錯誤的詳細資訊。

出現bug: 在學習celery,將資料儲存到redis時出現下面的bug。 consumer: Cannot connect to redis://192.168.12.188:6379/3: MISCONF Redis is configured to save RDB sn

session依賴cookie如果瀏覽器禁用cookie呢?

<form action='<%=response.encodeURL("/jsp/index.jsp") %>' method="post"> <

啟動虛擬機器會有錯誤報告:二進位制轉換與此平臺上的長模式不相容。此虛擬環境中的長模式將禁用因此需要使用長模式的應用程式將無法正常執行

1.先安裝VMware2.常建立虛擬機器3.啟動虛擬機器,啟動會有:二進位制轉換與此平臺上的長模式不相容。此虛擬環境中的長模式將被禁用,因此需要使用長模式的應用程式將無法正常執行  解決辦法:需要開啟BIOS系統把  Intel  Virtual Technology 改為e

解決VMWare中“二進位制轉換與此平臺上的長模式不相容此虛擬環境中的長模式將禁用”問題

    【轉自】http://blog.sina.com.cn/s/blog_63b15fc901019wkn.html 在使用Windows7 64位作業系統時,無法執行VMWare或MS Virtual server等軟體虛擬作業系統。提示為“提示:軟體虛擬化與此平臺上的長模式不相容. 禁用長模式.

關於word2016中mathtype無法使用以及“由於巨集安全設定無法找到巨集或巨集已禁用”的解決方案

版本描述:系統:win10 64位word: 2016版 32位Mathtype: 6.9d (6.9b也出現相同問題,應該可以通過相同的方法解決)問題描述:  自從在一次win10更新之後,word文件開啟時就會出現“由於巨集安全設定,無法找到巨集或巨集已被禁用”的提示。某些文件則提示“被另一使用者鎖定,無

使用QFileInfo類獲取檔案資訊(在NTFS檔案系統上出於效能考慮檔案的所有權和許可權檢查在預設情況下是被禁用通過qt_ntfs_permission_lookup開啟和操作。absolutePath()必須查詢檔案系統。而path()函式可以直接作用於檔名本身所以path() 函

版權宣告:本文為博主原創文章,未經博主允許不得轉載。 https://blog.csdn.net/Amnes1a/article/details/65444966QFileInfo類為我們提供了系統無關的檔案資訊,包括檔案的名字和在檔案系統中位置,檔案的訪問許可權,是否是目錄或符合連結,等等。並且,通過這個類

fsockopen禁用搞定discuz X2.5通訊實現單點登入登出

        空間安裝了discuz X2.5,安裝時提示fsockopen和pfsockopen函式被禁用,沒有理會繼續安裝,安裝過程沒出現錯誤但是進入後臺Ucenter卻發現通訊失敗,跟蹤了一下程式碼發現問題出現在uc_server/model/misc.php的9

【轉】SQL2008的sa賬戶禁用其他賬戶無法連線的解決方法

百度知道上搜來的,不過答案好像也是CSDN的。但我沒有找到地址,先貼出來方法備忘,侵刪。 或者你還有其它的sysadmin許可權的賬號,你可以用此賬號登入,重置SA密碼。 但是在以下情況下,怎麼辦呢? 1. SA密碼丟失或者SA賬號被禁用。 2. 你進行了一些安全操作,把B

XSS,CSRFCookie防劫持的處理

而是 java php xmlhttp 無效 可能 情況下 sca 憑證 Cookie與sessionHTTP天然是無狀態的協議, 為了維持和跟蹤用戶的狀態, 引入了Cookie和Session. Cookie包含了瀏覽器客戶端的用戶憑證, 相對較小. Session則維護

android開發中懸浮窗禁用無許可權開啟懸浮窗的解決方案

首先,感謝這兩篇博文http://blog.csdn.net/cankingapp/article/details/51569576 http://blog.csdn.net/cool_fuwei/article/details/53070232 瞭解知識:

Android檢查應用許可權是否禁用解決許可權禁用時程式崩潰

一、問題描述         在Android開發中,往往會用到許多諸如攝像頭、錄音等許可權。但是,我們都知道,小米、魅族等定製系統,或者360等安全軟體在程式請求開啟相機、錄音等操作時,會先彈出對話方塊提示使用者是否允許程式執行這些操作,如果使用者選擇允許則接下來的操作一

Win10輸入法無法選擇右下角出現叉號提示IME禁用

批處理來自動實現:schtasks /End /TN "\Microsoft\Windows\TextServicesFramework\MsCtfMonitor"schtasks /Run /TN "\Microsoft\Windows\TextServicesFrame