基于RFC6265 (HTTP状态管理协议)实现简单的登录系统

简介: 基于RFC6265 (HTTP状态管理协议)实现简单的登录系统

该协议主要是阐述如何利用HTTP Cookie与SetCookie头字段来实现对HTTP Request


状态的跟踪与管理,这个在用户行为分析,登录系统设计等方法有着很重要的应用。对


于大多数现代的浏览器都支持RFC6265.



基本原理:


RFC6265阐述通过设置SetCookie不同值在HTTPResponse中,来告诉浏览器客户端在


接下来的每次请求Request Header中都带上Response中指定的值与行为。直到服务器


配置的session过期为止。通过Tomcat配置session过期时间为30分钟,在web.xml配置


文件中可以重写该属性值。同时当用户关闭浏览器以后,在客户端内存中对于该站点


的cookie内容将会自动销毁。也许这样不太方便用户,于是很多网站提供了记住自己帐


号的原因,其实就是通过将cookie写到本地文件中。



系统访问与重定向到登录页面


首先当浏览器客户端发起一个Request请求访问指定URL或者Web Server时,服务器


端通过检查请求头是否含有Cookie字段,以及Cookie字段中的内容来设别访问者是否


为登录或者未登录用户,如果是未登录页面,则将URL重定向到登录页面即可。用户


登录以后服务器端发送一个HTTP Response + Set-Cookie内容到客户端浏览器,那么


在随后所有发往该Domain的URL都将会带上Set-Cookie中指定的内容,HTTP


Request + Cookie到服务器端,服务器端通过检查Request 头中Cookie内容实现对


用户的状态追踪。从而将无状态HTTP Request变成一个有状态的HTTP连接加以


管理。登录处理基本的流程图如下:

20140324010801312.png


服务器与客户端HTTP Request发送与接受状态:

20140324010834703.png


用户退出系统与Request状态终止


当客户端关闭浏览器时候,客户端Cookie将会被自动从内存中丢弃,当客户端再次打


开浏览器请求服务器端资源时候,将被要求再次登录到服务器端建立新的可跟踪的


Request 会话当超过服务器端配置的会话时间时,同样会要求用户再次登录系统。


当用户使用系统退出功能正常退出时,当退出时候通过设置Max-Age : 0来remove


当前cookie内容实现对客户端状态的清零。只要在HTTP Response中加上Cookie过


期属性同时设置一个过去的时间。例子如下:

20140324010934328.png


RFC6265中关于Cookie与SetCookie的属性与使用详解

image.png

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信息:

20140324010916015.png



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

全部源代码下载点击这里:

http://download.csdn.net/detail/jia20003/7087947

觉得好请顶一下啊!!,谢谢!!

相关文章
|
19天前
|
安全 网络协议 网络安全
IP代理的三大协议:HTTP、HTTPS与SOCKS5的区别
**HTTP代理**适用于基本网页浏览,简单但不安全;**HTTPS代理**提供加密,适合保护隐私;**SOCKS5代理**灵活强大,支持TCP/UDP及认证,适用于绕过限制。选择代理协议应考虑安全、效率及匿名需求。
|
18天前
|
安全 网络安全 数据安全/隐私保护
深入理解HTTP协议:工作原理与安全性
【6月更文挑战第28天】HTTP是互联网基础协议,用于浏览器与服务器通信。基于请求-响应模型,无状态且可扩展。但其明文传输、缺乏身份验证和数据完整性校验导致安全问题。HTTPS 加入SSL/TLS,提供加密、身份验证和完整性校验,保障网络安全。了解HTTP原理和安全至关重要。
|
3天前
|
网络协议 安全 Python
我们将使用Python的内置库`http.server`来创建一个简单的Web服务器。虽然这个示例相对简单,但我们可以围绕它展开许多讨论,包括HTTP协议、网络编程、异常处理、多线程等。
我们将使用Python的内置库`http.server`来创建一个简单的Web服务器。虽然这个示例相对简单,但我们可以围绕它展开许多讨论,包括HTTP协议、网络编程、异常处理、多线程等。
5 0
|
19天前
|
缓存 开发框架 网络协议
必知的技术知识:HTTP协议和SOCKS5协议
必知的技术知识:HTTP协议和SOCKS5协议
|
21天前
|
Web App开发 缓存 安全
HTTP协议 -JavaWeb基础必知
HTTP协议 -JavaWeb基础必知
23 0
|
25天前
|
机器学习/深度学习 前端开发 JavaScript
【计算机网络】深度学习使用应用层的HTTP协议
【计算机网络】深度学习使用应用层的HTTP协议
37 0
|
26天前
|
缓存 网络协议 应用服务中间件
深入理解 web 协议(一)- http 包体传输
深入理解 web 协议(一)- http 包体传输
|
SQL Web App开发 前端开发
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html><head><meta http-equiv="Cont
在运行一个group by的sql时,抛出以下错误信息: Task with the most failures(4):  -----Task ID:  task_201411191723_723592_m_000004URL:  http://DDS0204.
931 0
|
存储 监控 数据库
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html><head><meta http-equiv="Cont
为首次部署MongoDB做好准备:容量计划和监控 作者Mat Keep ,译者孙镜涛如果你已经完成了自己新的MongoDB应用程序的开发,并且现在正准备将它部署进产品中,那么你和你的运营团队需要讨论一些关键的问题: 最佳部署实践是什么? 为了确保应用程序满足它所必须的服务层次我们需要监控哪些关键指标? 如何能够确定添加分片的时机? 有哪些工具可以对数据库进行备份和恢复? 怎样才能安全地访问所有新的实时大数据? 本文介绍了硬件选择、扩展、HA和监控。
2572 0