zoukankan      html  css  js  c++  java
  • Session、Cookie、token

    一、Session

    销毁session 的2中方式

    1. session.invalidate() 实际开发极少用
    2. 当用户与服务器交互超过默认时间,Session 失效
    3. tomcat session 默认是30分钟失效

    当浏览器第一次访问Servlet 容器 会创建一个 HttpSession 的对象,HttpSession 对象存储的是用户的状态。当浏览器关闭的时候,session 并没有被销毁,session 有过期时间,会自动销毁

    当浏览器器第二次访问servlet ,会带 Cookie 信息,cookie 中的携带 JSESSIONID 的信息就是 Session 的 id .

    在同一个浏览器中同时打开多个标签,发送同一个请求或者不同的请求,是同一个session.不同的浏览器发送是不同的session.

    当把所有浏览器都关闭,在重新打开,是不同的session .但是之前的session 仍存在,只是浏览器的cookie 没有记录的化是无法访问的

    Session 的意义:

    提高安全性,将关键数据保存在服务端,与cookie 不同,cookie 将数据保存在客户端浏览器

    1.1 session 是如何产生的?

    Session 是一个会话的key,浏览器第一次访问服务器生成一个Session ,有一个sessionid 和它对应 。tomcat 生成的sessionid 叫做 jsessionid

    tomcat 创建sessionid 的过程:

    1.ManagerBase 提供创建的方法:随机数+时间+jvmid

    ManagerBase 是所有session 管理工具类的基类,它是一个抽象类,所有具体实现session管理功能都要继承改类

    ManagerBase 生成SessionIdGenerator ,SessionGenerator 是接口,具体的实现是  StandardSessionIdGenerator

       public SessionIdGenerator getSessionIdGenerator() {
            if (this.sessionIdGenerator != null) {
                return this.sessionIdGenerator;
            } else {
                if (this.sessionIdGeneratorClass != null) {
                    try {
                        this.sessionIdGenerator = (SessionIdGenerator)this.sessionIdGeneratorClass.getConstructor().newInstance();
                        return this.sessionIdGenerator;
                    } catch (ReflectiveOperationException var2) {
                    }
                }
    
                return null;
            }
        }

    接口SessionIdGenerator

    public interface SessionIdGenerator {
        String getJvmRoute();
    
        void setJvmRoute(String var1);
    
        int getSessionIdLength();
    
        void setSessionIdLength(int var1);
    
        String generateSessionId();
    
        String generateSessionId(String var1);
    }

    StandardSessionIdGenerator 生成SessionId 的具体方法: 

     public String generateSessionId(String route) {
            byte[] random = new byte[16];
            int sessionIdLength = this.getSessionIdLength();
            StringBuilder buffer = new StringBuilder(2 * sessionIdLength + 20);
            int resultLenBytes = 0;
    
            while(resultLenBytes < sessionIdLength) {
                this.getRandomBytes(random);
    
                for(int j = 0; j < random.length && resultLenBytes < sessionIdLength; ++j) {
                    byte b1 = (byte)((random[j] & 240) >> 4);
                    byte b2 = (byte)(random[j] & 15);
                    if (b1 < 10) {
                        buffer.append((char)(48 + b1));
                    } else {
                        buffer.append((char)(65 + (b1 - 10)));
                    }
    
                    if (b2 < 10) {
                        buffer.append((char)(48 + b2));
                    } else {
                        buffer.append((char)(65 + (b2 - 10)));
                    }
    
                    ++resultLenBytes;
                }
            }
    
            if (route != null && route.length() > 0) {
                buffer.append('.').append(route);
            } else {
                String jvmRoute = this.getJvmRoute();
                if (jvmRoute != null && jvmRoute.length() > 0) {
                    buffer.append('.').append(jvmRoute);
                }
            }
    
            return buffer.toString();
        }

    以上所有的类都是在Tomcat 容器包中。

    1.2 自定义生成sessionId

    public class GeneratorSession extends SessionIdGeneratorBase {
    
        @Override
        public String generateSessionId(String route) {
            byte[] random = new byte[16];
            int sessionIdLength = this.getSessionIdLength();
            StringBuilder buffer = new StringBuilder(2 * sessionIdLength + 20);
            int resultLenBytes = 0;
    
            while(resultLenBytes < sessionIdLength) {
                this.getRandomBytes(random);
    
                for(int j = 0; j < random.length && resultLenBytes < sessionIdLength; ++j) {
                    byte b1 = (byte)((random[j] & 240) >> 4);
                    byte b2 = (byte)(random[j] & 15);
                    if (b1 < 10) {
                        buffer.append((char)(48 + b1));
                    } else {
                        buffer.append((char)(65 + (b1 - 10)));
                    }
    
                    if (b2 < 10) {
                        buffer.append((char)(48 + b2));
                    } else {
                        buffer.append((char)(65 + (b2 - 10)));
                    }
    
                    ++resultLenBytes;
                }
            }
    
            if (route != null && route.length() > 0) {
                buffer.append('.').append(route);
            } else {
                String jvmRoute = this.getJvmRoute();
                if (jvmRoute != null && jvmRoute.length() > 0) {
                    buffer.append('.').append(jvmRoute);
                }
            }
    
            return buffer.toString();
        }
    
        public static void main(String[] args) {
            GeneratorSession generatorSession = new GeneratorSession();
            String sessionId = generatorSession.generateSessionId(null);
            System.out.println(sessionId);
        }
    }
    

     1.3 分析SessionId

    SessionId 的长度默认是16位

      private int sessionIdLength = 16;

    实际sessionid 长度是: 32 位

    tomcat 可以修改sessionId 的长度,使用的随机数算法是:SHA1PRNG  (SecurityRandom)

    二、Cookie

    Session 的使用离不开cookie ,因为 http协议是无状态的。Session 无法依据 Http 连接来判断是否为同一个客户。因此Session 需要cookie 在作为识别标志。当客户端连接到服务端 创建Session后,

    服务端向客户端浏览器发送名为 JSESSIONID 的 COOKIE ,JSESSIONID 的值就是Session 的id.Session 依据改Cookie 来识别是否为同一个用户。

    改Cookie 为浏览器自动生成的,它的 maxAge 属性一般为 -1,表示当前浏览器生效,并且各个浏览器不共享,关闭浏览器即失效

    如果客户端浏览器将 Cookie 功能禁用,或者不支持cookie解决办法?

    URL 地址重写,URL 地址重写是客户端不支持Cookie 的解决方案,原理是将改用户的Session Id信息重写到URL 地址中,服务器能够解析重写后的URL 获取Session 的id

    tomcat 判断客户端是否支持cookie 的依据是请求中是否包含 cookie .尽管客户端可能会支持Cookie,但是由于第一次请求时不会携带任何Cookie(因为并无任何Cookie可以携带),

    URL地址重写后的地址中仍然会带有jsessionid。当第二次访问时服务器已经在浏览器中写入Cookie了,因此URL地址重写后的地址中就不会带有jsessionid了。

    第一次请求:未携带 JSESSIONID

     第二次请求:携带的JSESSIONID

    三、Token

    token 的意思是 “令牌”,是用户身份验证的方式,最简单的 token 组成:uid(用户唯一标识)、time(当前时间戳)、sign(签名,由token 的前几位+盐 以哈希算法压缩成一定长的十六进制字符串,可以防止恶意第三方拼接 token 请求服务器)

    还可以把不变的参数也放进 token ,避免多次查库

    四、cookie 与 session 的区别

    1.cookie 数据存放在客户端的浏览器上,session 数据放在服务器上

    2.cookie 不是很安全,别人可以分析存放在本地的cookie 进行 cookie 欺骗,考虑安全应当使用session

    3.session 会在一定时间内保存到服务器上,当访问增加,会占用服务器性能,考虑服务器性能方面,应当使用 cookie

    4.单个 cookie 保存的数据不能超过 4K,很多浏览器限制一个站点最多保存 20 个cookie

    5.登录重要信息放在session 

      其他信息放在 cookie

    五、token 与 session 的区别

    session 和 oauth token  不矛盾,作为身份认证 token 安全性比session 好,因为每个请求都有签名还能防止监听以及重放攻击,而 session 就必须靠链路层来保障通讯安全。

    app 通常用 restful api 与 servlet 打交道,rest 是 stateless的,也就是 app 不需要像 浏览器那样用 cookie 来保存 session ,可以在 app 里嵌入 webkit ,用隐蔽的 browser 来管理cookie session.

       Session 是一种HTTP存储机制,目的是为无状态的HTTP提供的持久机制。所谓Session 认证只是简单的把User 信息存储到Session 里,因为SID 的不可预测性,暂且认为是安全的。这是一种认证手段。 
    而Token ,如果指的是OAuth Token 或类似的机制的话,提供的是 认证 和 授权 ,认证是针对用户,授权是针对App 。其目的是让 某App有权利访问 某用户 的信息。这里的 Token是唯一的。
    不可以转移到其它 App上,也不可以转到其它 用户 上。 转过来说Session 。Session只提供一种简单的认证,即有此 SID,即认为有此 User的全部权利。是需要严格保密的,这个数据应该只保存在站方,
    不应该共享给其它网站或者第三方App。 所以简单来说,如果你的用户数据可能需要和第三方共享,或者允许第三方调用 API 接口,用 Token 。如果永远只是自己的网站,自己的 App,用什么就无所谓了。   token就是令牌,比如你授权(登录)一个程序时,他就是个依据,判断你是否已经授权该软件;cookie就是写在客户端的一个txt文件,里面包括你登录信息之类的,这样你下次在登录某个网站,
    就会自动调用cookie自动登录用户名;session和cookie差不多,只是session是写在服务器端的文件,也需要在客户端写入cookie文件,但是文件里是你的浏览器编号.Session的状态是存储在服务器端,客户端只有session id;
    而Token的状态是存储在客户端。

     参考:https://blog.csdn.net/jikeehuang/article/details/51488020

    参考:https://mp.weixin.qq.com/s/8Nm6gQcrqqVRIF3JqJ4uAg

  • 相关阅读:
    UVA 10618 Tango Tango Insurrection
    UVA 10118 Free Candies
    HDU 1024 Max Sum Plus Plus
    POJ 1984 Navigation Nightmare
    CODEVS 3546 矩阵链乘法
    UVA 1625 Color Length
    UVA 1347 Tour
    UVA 437 The Tower of Babylon
    UVA 1622 Robot
    UVA127-"Accordian" Patience(模拟)
  • 原文地址:https://www.cnblogs.com/bytecodebuffer/p/11562251.html
Copyright © 2011-2022 走看看