• 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

  • 相关阅读:
    manacher算法笔记
    2019qbxtCSP-S2 模拟题1
    三元环计数
    踩坑日记
    我的Ubuntu16.04 安装配置
    SLAM14讲项目在 mac 上无法正常运行
    平面最近点对的算法实现
    hiho 1996
    【游记】NOIP2018 退役滚粗记
    铁板铮铮♂+习题集
  • 原文地址:https://www.cnblogs.com/bytecodebuffer/p/11562251.html
Copyright © 2020-2023  润新知