該協議主要是闡述如何利用HTTP Cookie與SetCookie頭字段來實現對HTTP Requestjava
狀態的跟蹤與管理,這個在用戶行爲分析,登陸系統設計等方法有着很重要的應用。對web
於大多數現代的瀏覽器都支持RFC6265.spring
基本原理:瀏覽器
RFC6265闡述經過設置SetCookie不一樣值在HTTPResponse中,來告訴瀏覽器客戶端在服務器
接下來的每次請求Request Header中都帶上Response中指定的值與行爲。直到服務器cookie
配置的session過時爲止。經過Tomcat配置session過時時間爲30分鐘,在web.xml配置session
文件中可以重寫該屬性值。同時當用戶關閉瀏覽器之後,在客戶端內存中對於該站點app
的cookie內容將會自動銷燬。也許這樣不太方便用戶,因而不少網站提供了記住本身賬ide
號的緣由,其實就是經過將cookie寫到本地文件中。網站
系統訪問與重定向到登陸頁面
首先當瀏覽器客戶端發起一個Request請求訪問指定URL或者Web Server時,服務器
端通過檢查請求頭是否含有Cookie字段,以及Cookie字段中的內容來設別訪問者是否
爲登陸或者未登陸用戶,若是是未登陸頁面,則將URL重定向到登陸頁面便可。用戶
登陸之後服務器端發送一個HTTP Response + Set-Cookie內容到客戶端瀏覽器,那麼
在隨後全部發往該Domain的URL都將會帶上Set-Cookie中指定的內容,HTTP
Request + Cookie到服務器端,服務器端經過檢查Request 頭中Cookie內容實現對
用戶的狀態追蹤。從而將無狀態HTTP Request變成一個有狀態的HTTP鏈接加以
管理。登陸處理基本的流程圖以下:
服務器與客戶端HTTP Request發送與接受狀態:
用戶退出系統與Request狀態終止
當客戶端關閉瀏覽器時候,客戶端Cookie將會被自動從內存中丟棄,當客戶端再次打
開瀏覽器請求服務器端資源時候,將被要求再次登陸到服務器端創建新的可跟蹤的
Request 會話當超過服務器端配置的會話時間時,一樣會要求用戶再次登陸系統。
當用戶使用系統退出功能正常退出時,當退出時候經過設置Max-Age : 0來remove
當前cookie內容實現對客戶端狀態的清零。只要在HTTP Response中加上Cookie過
期屬性同時設置一個過去的時間。例子以下:
RFC6265中關於Cookie與SetCookie的屬性與使用詳解
Cookie |
SetCookie |
包含於HTTP Request Header,用戶客戶端向服務器端發送驗證信息與其它有用信息,主要用來跟蹤客戶端狀態與分析用戶行爲 |
在HTTP Response中設置,主要用於服務器端向客戶端發送指定的狀態信息,創建與客戶端的聯繫。經過設置HTTPOnly屬性與Secure屬性還能夠保護客戶端Cookie數據,減小惡意讀取用戶Cookie信息發生。 |
RFC6265中一個簡單例子:
== Server -> UserAgent == // 服務器發送到客戶端
Set-Cookie:SID=31d4d96e407aad42
== User Agent ->Server == // 每一個請求中都會帶上SID信息,實現追蹤用戶狀態
Cookie: SID=31d4d96e407aad42
要求客戶端的全部請求路徑都要帶上SID信息,經過發送Path=/實現
== Server -> UserAgent ==
Set-Cookie:SID=31d4d96e407aad42; Path=/; Domain=example.com
== User Agent ->Server ==
Cookie: SID=31d4d96e407aad42
刪除客戶端Request Cookie中SID信息,取當前時間之前的一個任意時間。
== Server -> UserAgent ==
Set-Cookie: SID=;Expires=Sun, 06 Nov 1994 08:49:37 GMT
最後來看一看我抓取的CSDN登陸之後的Cookie信息:
J2EE 當從HTTP Servlet Request中調用獲取SessionID方法之後會自動把JSESSIONID
做爲Cookie設置到Response頭中。因此無需顯式再次調用!
根據RFC6265的內容,基於Spring3 MVC我本身也實現了一個簡單的登陸系統設計
能夠幫助你們更好的理解協議。只有兩個頁面,兩個Controller類與一個ServletFilter
各個類的做用大體以下:
ServletFilter類:實現對HTTP Request頭的檢查,跟蹤用戶狀態
兩個Controller類:一個用來管理用戶登入登出,一個是簡單的獲取主頁面信息
其中ServletFilter類代碼以下:
package com.edinme.exam.filter; import java.io.IOException; import java.util.Date; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.editme.exam.util.FilterUtil; public class SingleSignOnFilter implements Filter{ @Override public void destroy() { // TODO Auto-generated method stub } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest httpRequest = (HttpServletRequest) request; HttpServletResponse httpResponse = (HttpServletResponse) response; String ipAddress = httpRequest.getRemoteAddr(); // get URI resource path String uriPath = httpRequest.getRequestURI(); String contextPath = httpRequest.getContextPath(); String cookie = httpRequest.getHeader("Cookie"); String sessionId = httpRequest.getSession().getId(); // enable SetCookie header in HTTP Response if(FilterUtil.validURLRequest(uriPath, cookie, contextPath, sessionId)) { System.out.println("Request URI : " + uriPath); System.out.println("IP "+ipAddress + ", Time " + new Date().toString()); chain.doFilter(request, response); } else { System.out.println(httpRequest.getProtocol() + httpRequest.getLocalPort() + httpRequest.getContextPath()); httpResponse.sendRedirect("/exam/user.do"); } } @Override public void init(FilterConfig config) throws ServletException { // TODO Auto-generated method stub } }
用戶登入登出Controller:
package com.edinme.exam.controller; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.servlet.ModelAndView; import com.edinme.exam.dto.MockUpDataFactory; import com.edinme.exam.dto.UserDto; import com.editme.exam.util.FilterUtil; @Controller @RequestMapping(value = "/user") public class UserLoginController { @RequestMapping(method = RequestMethod.GET) public ModelAndView goLoginPage() { System.out.println("Dispaly SSO Page"); ModelAndView view = new ModelAndView("user"); return view; } @RequestMapping(value = "signIn", method = RequestMethod.GET) @ResponseBody public UserDto login(@RequestParam String userId, @RequestParam String password, /*HttpServletRequest httpRequest,*/ HttpServletResponse response) { System.out.println("User Name = " + userId); MockUpDataFactory dataFactory = new MockUpDataFactory(); response.addHeader("Set-Cookie", "userId=" + userId + "; Path=" + FilterUtil.CONTEXT_PATH + "; HttpOnly"); return dataFactory.getUserById(userId); } @RequestMapping(value = "signOut", method = RequestMethod.GET) @ResponseBody public UserDto logout(@RequestParam String userId, HttpServletRequest httpRequest, HttpServletResponse response) { MockUpDataFactory dataFactory = new MockUpDataFactory(); // Set-Cookie:JSESSIONID=delete; Expires=Thu, 01-Jan-1970 00:00:10 GMT; Path=/exam/ // Set-Cookie:userId=delete; Expires=Thu, 01-Jan-1970 00:00:10 GMT; Path=/exam/ Cookie[] cs = httpRequest.getCookies(); for(Cookie c : cs) { c.setMaxAge(0); // set expire attribute c.setValue("delete"); c.setPath(FilterUtil.CONTEXT_PATH); // set path, must be same as login context path response.addCookie(c); } response.setHeader("Expires", "Thu, 19 Nov 1981 08:52:00 GMT"); // must be GTM format return dataFactory.getUserById(userId); } // // public static void main(String[] args) // { // SimpleDateFormat sdf = new SimpleDateFormat("E dd MMM yyyy HH:mm:ss zzz", Locale.ENGLISH); // sdf.setTimeZone(TimeZone.getTimeZone("GMT")); // System.out.println(sdf.format(new Date())); // } }
所有源代碼下載點擊這裏:
以爲好請頂一下啊!!,謝謝!!