美文网首页nodejs
node.js学习(11)——cookie和session的使用

node.js学习(11)——cookie和session的使用

作者: YINdevelop | 来源:发表于2019-05-23 16:10 被阅读0次

    上一节-node.js学习(10)—express中间件—body-parser获取post、get数据

    上节我们讲了如何在express中获取post、get数据,这一节我们讲解cookie和session。


    20190523164210.png

    1.给浏览器发送( response ) cookie

    我们在server.js添加如下代码

    const express=require('express');
    const server=express();
    
    server.use('/test', function (req, res){
        if (req.url === '/favicon.ico') {
            return
        }
        res.cookie('user', 'blue'); //发送cookie给浏览器,让浏览器来写入cookie
        res.send('hello cookie');
    });
    
    server.listen(8080);
    
    1. 在express中,它已经为我们封装好了操作cookie的方法,我们使用res.cookie来发送cookie
    2. 上面代码表示在 /test路径下,设置cookie为key:user,value:blue
    3. 如果设置多个cookie,需要写多行res.cookie
    4. 除下设置key/value,还可以添加其他参数,如path,http,domain.maxAge,expires等,具体可以看express文档-res.cookie
        res.cookie('user', 'blue',{
            path:'/',
            httpOnly:false
            ...
        })
    

    启动服务,打开浏览器并访问/test路径,我们可以在控制台找到我们刚设置的cookie。

    20190520163526.png

    2.服务器接收浏览器传过来的( request ) cookie

    上面我们讲了服务端如何发送cookie给浏览器,并且也知道浏览器访问服务器url,会先检查url下有没有cookie,有的话在访问过程中,会将cookie自动添加到请求头中,那么服务器如何从请求头中获取cookie呢?

    我们修改server.js

    const express=require('express');
    const cookieParser=require('cookie-parser');
    const server=express();
    server.use(cookieParser())
    server.use('/test', function (req, res){
        if (req.url === '/favicon.ico') {
            return
        }
        res.cookie('user', 'blue'); //设置cookie
        res.cookie('user1', 'blue1'); //设置cookie
        console.log(req.cookies) //{"user": "blue","user1":"blue1"}
        res.send(req.cookies);
    });
    
    server.listen(8080);
    
    1. express默认需要引入cookie-parser模块(安装express会自动安装,不用单独安装,只需要引入即可)才能获取浏览器传过来的cookie。
    2. 使用req.cookies获取浏览器传过来的cookie,值为对象。

    在浏览器中运行上面代码,如下图:

    1. 第一次req.cookies为空,浏览器写入cookie
    2. 第二次浏览器发送之前写入的cookie,req.cookies有值
    rrr.gif

    3.cookie签名(防服务器数据篡改)

    何谓篡改,我们都知道,cookie是保存在客户端的,我们可以通过js或者直接在控制台修改cookie的,这样会暴露一个问题:

    1. 浏览器发起一个修改用户信息的请求,带上Cookie信息username=aa(前提已经种下cookie),服务器接收到请求后,会去修改username为aa的数据
    2. 如果用户知道username字段表示用户名信息,那么他把值改为bb,然后再次发起请求,服务器接收到请求,去修改username为bb用户的数据(假如数据库中刚好有个username为bb的用户)
    3. 这样因为cookie被用户修改,导致服务器数据被篡改的风险

    怎么防止篡改?就有了cookie签名的由来。

    1. 假设现在有个cookie(username=blue),服务器在发送cookie给浏览器之前先配置一个秘钥(如sdfjk7777),通过sha256或者其他加密算法(这里假设加密方法为secret()),然后使用secret('blue','sdfjk7777')生成一个签名和cookie值组合(类似{username:s:blue.3byMSHd31XkJ0JszpW7IXndQaUh6XFLxks+6/zWRdXg}
    2. 其中blue表示真正的值,后面是签名。假如我现在把blue改成blue1。
    3. 当浏览器再次发送请求时,服务器取出签名(因为太长了,这里叫A)以及cookie真正的值(blue1)。然后使用之前的加密算法判断secret('blue1','sdfjk7777')==A,如果不相等,说明cookie被恶意修改了。

    4.使用cookie-parser增加cookie签名

    我们修改server.js

    const express=require('express');
    const cookieParser=require('cookie-parser');
    const server=express();
    //增加一个随机秘钥
    server.use(cookieParser('asdfd45556'))
    
    server.use('/test', function (req, res){
        if (req.url === '/favicon.ico') {
            return
        }
        res.cookie('user', 'blue',{
            signed:true
        });
        res.cookie('user1', 'blue1'); 
        console.log(req.cookies); //无签名cookie {user1:blue1}
        console.log(req.signedCookies); //签名cookie {user:blue}
        console.log(req.headers.cookie) //浏览器发过来的cookie: user1=blue1; user=s%3Ablue.3byMSHd31XkJ0JszpW7IXndQaUh6XFLxks%2B6%2FzWRdXg
        res.send('ok'); //由于res.send默认最后一个生效(相当于只能写一个),所以上面用console.log代替输出
    });
    
    server.listen(8080);
    
    1. 将秘钥 asdfd45556传入cookieParser函数中,然后在需要签名的cookie增加参数 signed:true
    2. 此时cookie会分割成两个属性 cookies-未签名的、signedCookies-已签名的
    3. 注意:req.signCookies的值为签名的cookie原始值,不带签名字符串,阅读cookie-parser源码,其将签名去除然后再赋到signCookies上
    4. 可以通过req.header.cookie获取浏览器带过来的cookie
    20190521163546.png

    上图中,s%3Ablue.3byMSHd31XkJ0JszpW7IXndQaUh6XFLxks%2B6%2FzWRdXg为签名cookie,实际上是该值是先签名后encodeURIComponent编码过来的。我们可以解码看

    console.log(decodeURIComponent('s%3Ablue.3byMSHd31XkJ0JszpW7IXndQaUh6XFLxks%2B6%2FzWRdXg')) 
    //s:blue.3byMSHd31XkJ0JszpW7IXndQaUh6XFLxks+6/zWRdXg
    

    其中,s:表示签名,blue为真正的值,后面的是签名

    所以我们在浏览器实际上仍可以看见用户信息,cookie签名并不能起到加密作用,只是防篡改作用。

    5.cookie-session

    之前在cookie和session区别曾讲过seesion。下面我们通过nodejs来实现session的demo(判断用户是否来过,保持用户登陆状态)

    server.js代码如下:

    const express=require('express');
    // const cookieParser=require('cookie-parser');
    const cookieSession=require('cookie-session');
    const server=express();
    // server.use(cookieParser())
    server.use(cookieSession({
        keys: ['aaa', 'bbb', 'ccc'], //session用来生成签名的列表,必填
        name: 'sessionId', //session名字,可省略,实测默认名字为'express:sess'
        cookie:{      //session配置
            //cookie选项
            path:'',
            ...
        }
    }))
    
    server.get('/test', function (req, res){
        if (req.url === '/favicon.ico') {
            return
        }
        console.log(req.session); //第一次为{},后面为{hasCome:true}
        // console.log(req.cookies); 
        // console.log(req.signedCookies); 
        if(!req.session['hasCome']){
            req.session['hasCome']=true //写入hasCome属性
            res.send('欢迎第一次');
        }else{
            res.send('欢迎再次来');
        }
    });
    
    server.listen(8080);
    
    1. 使用session依赖cookie-session中间件,和cookie-parse不一样,需要单独安装,express不带。
    2. 该中间件使用必须传一个key数组,用来的session进行签名,和cookie签名一样,用来防止篡改,校验。name可以不传默认为express:sess
    3. 使用该中间件,session保存在cookie中,所以额外配置项就是cookie选项。所以如果expires/maxAge不传,即N/A,会话cookie,浏览器关闭即过期。
    4. 引入该中间件,req上面会增加session属性。demo中第一次进来session为空,不存在hasCome属性(判断是否已经来过),所以写入该属性,页面返回欢迎第一次,后面再次访问,req.session为{hasCome:true},页面返回欢迎再次来,可以看下图req.session打印状态以及页面展示内容
    tesw.gif
    1. 我们通过req.session可以很方便的访问session,由于该session对应的id是保存在cookie中,所以我们仍可以引用cookie-parser在cookie中查看sessionId(注意:虽然sessionId有签名,但是该插件将sessionId存在req.cookies属性中,不在req.signedCookies中,所以通过req.signedCookies是无法访问到的)

    现在我们把之前server.js的代码中注释的cookie-parser等代码解开注释,可以看到打印结果:

    console.log(req.cookies) 
    //结果为
    {
      sessionId: 'eyJoYXNDb21lIjp0cnVlfQ==',
      'sessionId.sig': 'moOOM66p-CAR9aeTORKkuBYXFk4'
    }
    
    console.log(req.signCookies) 
    //结果为
    {}
    
    1. 从session的格式来看,签名是单独为一个sessionId.sig字段,和之前使用cookie-parser签名一个cookie不一样(之前直接在cookie上拼接签名)
    20190523154833.png
    1. 如果session值变化,sessionId以及签名sessionId.sig会跟着变化。我们再换个demo(记录页面访问次数)测试下

    更改server.js代码:

    const express=require('express');
    const cookieSession=require('cookie-session');
    const server=express();
    server.use(cookieSession({
        keys: ['aaa', 'bbb', 'ccc'],
        name: 'sessionId', 
    }))
    
    server.get('/test', function (req, res){
        if (req.url === '/favicon.ico') {
            return
        }
        //count字段表示页面访问次数
        if(!req.session['count']){
            req.session['count']=1
        }else{
            req.session['count']++
        }
        res.send(''+req.session['count'])
    });
    
    server.listen(8080);
    

    页面测试结果:

    count1.gif

    相关文章

      网友评论

        本文标题:node.js学习(11)——cookie和session的使用

        本文链接:https://www.haomeiwen.com/subject/taydzqtx.html