文章目录
Cookie 、Session 、Token
HTTP 协议是一种无状态协议,即每次服务端接收到客户端的请求时,都是一个全新的请求,服务器并不知道客户端的历史请求记录;Session 和 Cookie 的主要目的就是为了弥补 HTTP 的无状态特性。
1、Cookie
1.1、cookie 简介
HTTP 协议中的 Cookie 包括 Web Cookie和浏览器 Cookie,它是服务器发送到 Web 浏览器的一小块数据。服务器发送到浏览器的 Cookie,浏览器会进行存储,并与下一个请求一起发送到服务器。通常,它用于判断两个请求是否来自于同一个浏览器,例如用户保持登录状态。
1.2、Cookie 核心技术
Cookie技术:会话数据保存在浏览器客户端。
Cookie类:用于存储会话数据
1.构造Cookie对象
Cookie(java.lang.String name, java.lang.String value)
2.设置cookie
void setPath(java.lang.String uri)
:设置cookie的有效访问路径
void setMaxAge(int expiry)
: 设置cookie的有效时间
void setValue(java.lang.String newValue)
:设置cookie的值
- 发送cookie到浏览器端保存
void response.addCookie(Cookie cookie)
: 发送cookie
4.服务器接收cookie
Cookie[] request.getCookies()
: 接收cookie
1.3、Cookie 原理
1.服务器创建cookie对象,把会话数据存储到cookie对象中
new Cookie("name","value");
2.服务器发送cookie信息到浏览器
response.addCookie(cookie);
举例: set-cookie: name=eric (隐藏发送了一个set-cookie名称的响应头)
3.浏览器得到服务器发送的cookie,然后保存在浏览器端。
4.浏览器在下次访问服务器时,会带着cookie信息
举例: cookie: name=eric (隐藏带着一个叫cookie名称的请求头)
5.服务器接收到浏览器带来的cookie信息
request.getCookies();
1.4、Cookie 细节
1.void setPath(java.lang.String uri)
:设置cookie的有效访问路径。
有效路径指的是cookie的有效路径保存在哪里,那么浏览器在有效路径下访问服务器时就会带着cookie信息,否则不带cookie信息。
2.void setMaxAge(int expiry)
: 设置cookie的有效时间。
正整数:表示cookie数据保存浏览器的缓存目录(硬盘中),数值表示保存的时间。
负整数:表示cookie数据保存浏览器的内存中。浏览器关闭cookie就丢失了!!
零:表示删除同名的cookie数据
3.Cookie数据类型只能保存非中文字符串类型的。
可以保存多个cookie,但是浏览器一般只允许存放300个Cookie,每个站点最多存放20个Cookie,每个Cookie的大小限制为4KB。
//案例- 显示用户上次访问的时间
@WebServlet("/LastAccessTime")
public class LastAccessTime extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=utf-8");// 防止浏览器显示乱码
String lastAccessTime = null;
//服务器接收来自游览器的cookie
Cookie[] cookies = req.getCookies();
for (Cookie cookie : cookies) {
String name = cookie.getName();
if (name.equals("lastAccessTime")) {
lastAccessTime = cookie.getValue();
break;
}
}
if (StringUtils.isEmpty(lastAccessTime)) {
resp.getWriter().print("您是首次访问!");
} else {
resp.getWriter().print("你上次访问时间:" + lastAccessTime);
}
// 保存访问时间
// 创建cookie 将当前时间作为cookie保存到浏览器
String currenttime = new SimpleDateFormat("yyyy-mm-dd hh:mm:ss").format(new Date());
//创建Cookie对象
Cookie cookie = new Cookie("lastAccessTime", currenttime);
//设置cookie的有效时间
cookie.setMaxAge(60 * 60 * 24);
// 发送cookie到游览器
resp.addCookie(cookie);
}
String addCookie(String key, String value, HttpServletResponse resp) {
return key;
}
}
2、Session
2.1、session 简介
客户端请求服务端,服务端会为这次请求开辟一块内存空间,这个对象便是 Session 对象,存储结构为 ConcurrentHashMap
。Session 弥补了 HTTP 无状态特性,服务器可以利用 Session 存储客户端在同一个会话期间的一些操作记录。
Session是服务器端技术,利用这个技术,服务器在运行时可以为每一个用户的数据创建一个其独享的Session对象,由于Session为用户浏览器独享,所以当用户在访问服务器的web资源时,可以把各自的数据放在各自的Session中,当用户再去访问服务器中的其他的web资源的时候,其他的web资源再从用户各自的Session中取出数据为用户服务。
2.2、Session 引入
Cookie的局限:
1)Cookie只能存字符串类型。不能保存对象
2)只能存非中文。
3)1个Cookie的容量不超过4KB。
如果要保存非字符串,超过4kb内容,只能使用session技术!!!
Session特点:会话数据保存在服务器端。(内存中)
2.3、session 缺点
Session 机制有个缺点,比如 A 服务器存储了 Session,就是做了负载均衡后,假如一段时间内 A 的访问量激增,会转发到 B 进行访问,但是 B 服务器并没有存储 A 的 Session,会导致 Session 的失效。
2.4、session 技术核心
HttpSession类:用于保存回话数据
1.创建或得到session对象
HttpSession getSession()
直接创建一个session对象
HttpSession getSession(boolean create)
接收布尔值,设置为true,没有匹配的session编号,自动创建新的session对象;设置为false,没有匹配的session编号,返回为null
2.设置session对象
void setMaxInactiveInterval(int interval)
: 设置session的有效时间
java.lang.String getId()
: 得到session编号
void invalidate()
: 销毁session对象
3.保存会话数据到session对象
void setAttribute(java.lang.String name, java.lang.Object value)
: 保存数据
java.lang.Object getAttribute(java.lang.String name)
: 获取数据
void removeAttribute(java.lang.String name)
: 清除数据
2.5、session 原理
问题: 服务器能够识别不同的浏览者!!!
前提: 在哪个session域对象保存数据,就必须从哪个域对象取出!!!!
浏览器1:(给s1分配一个唯一的标记:s001,把s001发送给浏览器)
1)创建session对象,保存会话数据
HttpSession session = request.getSession();
//保存会话数据 s1
浏览器1 的新窗口(带着s001的标记到服务器查询,s001–>s1,返回s1)
1)得到session对象的会话数据
HttpSession session = request.getSession();
//可以取出 s1
新的浏览器1:(没有带s001,不能返回s1)
1)得到session对象的会话数据
HttpSession session = request.getSession();
//不可以取出 s2
浏览器2:(没有带s001,不能返回s1)
1)得到session对象的会话数据
HttpSession session = request.getSession();
//不可以取出 s3
代码解读:HttpSession session = request.getSession();
1)第一次访问创建session对象,给session对象分配一个唯一的ID,叫JSESSIONID
new HttpSession();
2)把JSESSIONID作为Cookie的值发给游览器保存
Cookiecookie = new Cookie("JSESSIONID",sessionID);
request.addCookie(cookie);
3)第二次访问时,游览器带着JSESSIONID的cookie访问服务器
4)服务器得到JSESSIONID,在服务器的内存中搜索是否存放对应编号的session对象
if(找到){
return map.get(sessionID);
}
Map<String,HttpSession>
<"s001", s1>
<"s001,"s2>
5)如果找到对应编号的session对象,直接返回该对象
6)如果找不到对应编号的session对象,创建session对象,继续走 1)流程
结论:通过JSESSIONID的cookie值在服务器找session对象
2.6、session 细节
1)java.lang.String.getId() :得到session编号
2)两个getSession方法
getSession(true)/getSession()
:创建或得到session对象。没有匹配的session编号,自动创建新的session对象
getSession(false)
:得到session对象,没有匹配的session编号,返回null
3)void serMaxInactiveInterval(int interval) :设置session的有效时间
session对象销毁时间:
3.1 默认情况30分钟服务器自动回收
3.2 修改session回收时间
3.3 全局修改session有效时间
session.setMaxInactiveInterval(30 * 60);
<!-- 修改session全局有效时间:分钟 -->
<session-config>
<session-timeout>30</session-timeout>
</session-config>
3.4 手动销毁session对象
void invalidate() : 销毁session对象
4)如何避免游览器的JSESSION的cookie随游览器关闭而丢失问题
/**
* 手动发送一个硬盘保存的cookie给浏览器
*/
Cookie c = ***\*new\**** Cookie("JSESSIONID",session.getId());
c.setMaxAge(60*60);
response.addCookie(c);
Cookie和Session总结
1)会话:游览器和服务器之间的数据传输
2)会话管理:游览器和服务器会话过程中产生的会话数据的管理
3)Cookie技术:
new Cookie("name","value")
response.addCookie(coookie)
request.getCookies()
4)Session技术:
request.getSession();
setAttrbute("name","会话数据");
getAttribute("会话数据")
3、token
3.1、token简介
令牌,是用户身份的验证方式。 最简单的token组成:uid(用户唯一的身份标识)、time(当前时间的时间戳)、sign(签名)。
在对接一些第三方平台的时候,为了能够保证数据安全性,通常会使用一些令牌进行交互
3.2、token定义
token生成规则,只要保证token生成一个不重复的唯一字符串即可。
使用jdk自带的uuid生成规则。
3.3、UUID是什么
UUID含义是通用唯一识别码 (Universally Unique Identifier),这是一个软件建构的标准,也是被开源软件基金会 (Open Software Foundation, OSF) 的组织应用在分布式计算环境 (Distributed Computing Environment, DCE) 领域的一部分。
UUID 的目的,是让分布式系统中的所有元素,都能有唯一的辨识资讯,而不需要透过中央控制端来做辨识资讯的指定。如此一来,每个人都可以建立不与其它人冲突的 UUID。
在这样的情况下,就不需考虑数据库建立时的名称重复问题。目前最广泛应用的 UUID,即是微软的 Microsoft’s Globally Unique Identifiers (GUIDs),而其他重要的应用,
则有 Linux ext2/ext3 档案系统、LUKS 加密分割区、GNOME、KDE、Mac OS X 等等
- 一个Token就是一些信息的集合;
- 在Token中包含足够多的信息,以便在后续请求中减少查询数据库的几率;
- 服务端需要对cookie和HTTP Authrorization Header进行Token信息的检查;
- 基于上一点,你可以用一套token认证代码来面对浏览器类客户端和非浏览器类客户端;
- 因为token是被签名的,所以我们可以认为一个可以解码认证通过的token是由我们系统发放的,其中带的信息是合法有效的;
3.4、UUID组成
UUID保证对在同一时空中的所有机器都是唯一的。通常平台会提供生成的API。按照开放软件基金会(OSF)制定的标准计算,用到了以太网卡地址、纳秒级时间、芯片ID码和许多可能的数字。
UUID由以下几部分的组合:
(1)当前日期和时间,UUID的第一个部分与时间有关,如果你在生成一个UUID之后,过几秒又生成一个UUID,则第一个部分不同,其余相同。
(2)时钟序列。
(3)全局唯一的IEEE机器识别号,如果有网卡,从网卡MAC地址获得,没有网卡以其他方式获得。
UUID的唯一缺陷在于生成的结果串会比较长。关于UUID这个标准使用最普遍的是微软的GUID(Globals Unique Identifiers)。在ColdFusion中可以用CreateUUID()函数很简单地生成UUID,其格式为:xxxxxxxx-xxxx- xxxx-xxxxxxxxxxxxxxxx(8-4-4-16),其中每个 x 是 0-9 或 a-f 范围内的一个十六进制的数字。而标准的UUID格式为:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx (8-4-4-4-12);
3.5、UUID代码
public class UuidUtil {
public static String get32UUID() {
String uuid = UUID.randomUUID().toString().trim().replaceAll("-", "");
return uuid;
}
}
public final class UUID implements java.io.Serializable, Comparable<UUID> {
public static UUID randomUUID() {
SecureRandom ng = Holder.numberGenerator;
byte[] randomBytes = new byte[16];
ng.nextBytes(randomBytes);
randomBytes[6] &= 0x0f; /* clear version */
randomBytes[6] |= 0x40; /* set to version 4 */
randomBytes[8] &= 0x3f; /* clear variant */
randomBytes[8] |= 0x80; /* set to IETF variant */
return new UUID(randomBytes);
}
}