node学习-cookie和session

cookie

cookie的处理
  • 在web应用中,多个请求之间共享“用户会话”是非常必要的。但HTTP协议是无状态的。那这时cookie就出现了。那cookie又是如何处理的呢?
  1. 服务端向客户端发送cookie
  2. 客户端的浏览器把Cookie保存
  3. 然后在每次请求浏览器都会将Cookie发送到服务端
cookie使用的注意事项:
  1. 可能被客户端篡改,使用前验证其合法性
  2. 不要存储敏感数据,比如用户密码,账户余额等
  3. 使用httponly保证安全
  4. 尽量减少cookie的体积,这是由于浏览器对于每个域名所包含的cookie数和cookie的总大小有一定的限制
向服务端发送cookie
  • 在HTML文档被发送之前,Web服务器通过传送HTTP包头中的Set-Cookie消息把一个cookie发送到用户的浏览器中,如下所示:
    Set-Cookie:name=zhangjie;Expires=Fri, 01 Jun 2018 07:21:59 GMT
cookie设置中常用属性:
  • name=value:键值对,可以设置要保存的Key/Value,注意这里的那么不能和其它的属性项的名字一样
  • Expires:过期时间(单位ms),在设置的某个时间点后该Cookie就会失效,例如 Expires=Fri, 01 Jun 2018 07:41:15 GMT,在这个时间点后,cookie就会失效
  • Max-Age:最大失效时间(单位s),设置在多长时间之后失效
  • Secure: 设置为true时,表示创建的 Cookie 会被以安全的形式向服务器传输,也就是只能在 HTTPS 连接中被浏览器传递到服务器端进行会话验证,如果是 HTTP 连接则不会传递该信息,所以不会被窃取到Cookie 的具体内容。同上,在客户端我们也无法在document.Cookie找到被设置了Secure=true的Cookie键值对。Secure属性是防止信息在传递的过程中被监听捕获后信息泄漏,HttpOnly属性的目的是防止程序获取Cookie后进行攻击。我们可以把Secure=true看成比HttpOnly更严格的访问控制
  • path: 指定可访问Cookie的目录。例如:“userId=320; path=/shop”;就表示当前Cookie仅能在shop路径下使用
  • HttpOnly: 这是微软对Cookie做的扩展。如果在Cookie中设置了"HttpOnly"属性,那么通过程序(JS脚本、Applet等)将无法读取到Cookie信息,这样能有效的防止XSS攻击
  • domain: 指定可访问Cookie的主机名.主机名是指同一个域下的不同主机,例如:www.google.com和gmail.google.com就是两个不同的主机名。默认情况下,一个主机中创建的Cookie在另一个主机下是不能被访问的,但可以通过domain参数来实现对其的控制,其语法格式为:“name=value; domain=CookieDomain”;以google为例,要实现跨主机访问,可以写为:“name=value;domain=.google.com”;这样,所有google.com下的主机都可以访问该Cookie

如下:如果用户为第一次访问,那么输出“欢迎首次访问”,此时服务端已向客户端发送cookie,并且客户端已将cookie进行保存,当再次访问时,cookie将会放置在请求头中发送到服务端,此时输出“欢迎再次访问”

let http = require('http');
let url = require('url');
let querystring = require('querystring');

http.createServer((req,res)=>{
    let urlObj = url.parse(req.url,true);
    let pathname = urlObj.pathname;
    if (pathname === '/cookie'){
        res.setHeader('Content-Type','text/plain;charset=utf-8')
        let cookie = req.headers.cookie || {};
        let cookieObj = querystring.parse(cookie,';'); // 将请求头中的cookie信息转为对象格式
        if (cookieObj.isVisited){   // 如果存在cookie那么视为再次访问
            res.end('欢迎再次访问');
        }else{     // 如果不存在,那么向客户端发送cookie信息
            res.setHeader('Set-Cookie','isVisited=1;Max-Age=30');
            res.end('欢迎首次访问');
        }
    }
}).listen('8090');

下面使用cookie-parser重写上面的demo

	let express = require('express');
	let cookieParser = require('cookie-parser');
	
	let app = express();
	
	app.use(cookieParser());
	
	app.get('/cookie',(req,res)=>{
	    let cookies = req.cookies||{};
	    if (cookies.isVisited){
	        res.send('欢迎再次访问');
	    }else {
	        res.cookie('isVisited','1',{maxAge:10*1000});
	        res.send('欢迎首次访问');
	    }
	});
	
	app.listen('8090');

session

session介绍

cookie 虽然很方便,但是使用 cookie 有一个很大的弊端,cookie 中的所有数据在客户端就可以被修改,数据非常容易被伪造,那么一些重要的数据就不能存放在 cookie 中了,而且如果 cookie 中数据字段太多会影响传输效率。为了解决这些问题,就产生了 session,session 中的数据是保留在服务器端的,那什么是session呢?

  • session是一种记录客户端状态的机制,不同的是cookie保存在客户端浏览器中,而session保存在服务器上。
  • 客户端浏览器访问服务器的时候,服务器把客户端信息以某种形式记录在服务器上,这就是session。客户端浏览器再次访问时,只需要从该session中查找该客户的状态就可以了。
  • 如果说cookie机制是通过检查客户身上的“通行证”来确定客户身份的话,那么session机制就是通过检查服务器上的“客户明细表”来确认客户身份
  • session相当于在服务器上建立的一份客户档案,客户来访的时候只需要查询客户档案表就可以了
session处理
  1. 在服务器端生成全局唯一标识符(session_id)
  2. 在服务器内存里开辟此session_id对应的数据存储空间
  3. 将session_id作为全局唯一标识符通过cookie发送到客户端
  4. 以后客户端再次访问服务器时,会把session_id通过请求头中的cookie发送到服务端
  5. 服务器再通过session_id把此标识符在服务器端的数据取出

如下demo所示:我们创建了一个会员的信息,如果当前会员不存在,那么创建会员信息,并将会员id即session_id返回,如果会员存在,那么通过session_id获取会员的详细信息:

let http = require('http');
let url = require('url');
let queryString = require('querystring');

let SESSION_KEY = 'session_key';
let session = {};

http.createServer(function(req,res){
    let urlObj = url.parse(req.url,true);
    let pathname = urlObj.pathname;
    let membershipPoint = {point:100};
    if (pathname === '/'){
        let cookie = req.headers.cookie || {};
        let cookieObj = queryString.parse(cookie,';');
        if (cookieObj[SESSION_KEY]){     // 如果当前session_key存在,那么为老会员,并通过session_id获取其会员的会员详细信息
            let curSessionObj = session[cookieObj[SESSION_KEY]];
            res.setHeader('Content-Type','text/html;charset=utf-8');
            if (curSessionObj.point === 0 || curSessionObj.point < 0){
                res.end('欢迎您,老朋友,您的余额已使用完毕');
            }else {
                curSessionObj.point -= 10;
                res.end('欢迎您,老朋友,再次光临,余额为'+curSessionObj.point);
            }
        }else{     // 如果当前session_key不存在,那么为新会员,并建立其会员卡,余额为100,并将会员id即session_id返回给客户端
            let session_id = Date.now()+Math.random();
            session[session_id] = membershipPoint;
            res.setHeader('Set-Cookie',SESSION_KEY+'='+session_id);
            res.setHeader('Content-Type','text/html;charset=utf-8');
            res.end('欢迎您,新朋友,送您会员卡,余额为'+session[session_id].point);
        }
    }

}).listen('8090');

express-session

express中ssession的操作需要使用express-session这个模块,主要方法是session(options),其中option中包含可选参数,如下:

  • name:设置cookie中,保存session的字段名称,默认为:connect.sid
  • store:session的存储方式,默认存放在内存中, 也可以使用 redis,mongodb 等。express 生态中都有相应模块的支持
  • secret: 通过设置的 secret 字符串,来计算 hash 值并放在 cookie 中,使产生的 signedCookie 防篡改
  • cookie: 设置存放 session id 的 cookie 的相关选项,默认为
    • (default: { path: ‘/’, httpOnly: true, secure: false, maxAge: null })
  • genid: 产生一个新的 session_id 时,所使用的函数, 默认使用 uid2 这个 npm 包
  • rolling: 每个请求都重新设置一个 cookie,默认为 false
  • resave: 即使 session 没有被修改,也保存 session 值,默认为 true
  • saveUninitialized:保存新创建但未修改的session

使用express-session重写上面的demo,如下:

let express = require('express');
let session = require('express-session');
let app = express();

let SESSION_KEY = 'session_key';

app.use(session({
    name:SESSION_KEY,
    resave:true,    // 每次请求结束,都要重新保存,不管有没有修改
    saveUninitialized:true, //保存未修改过的session
    secret:'somesecrettoken'    // 加密的密钥
}));

app.get('/session',(req,res)=>{
    if (req.session.point != undefined){
        if (req.session.point === 0 || req.session.point < 0){
            res.send('欢迎您,老朋友,您的余额已使用完毕');
        }else {
            req.session.point -= 10;
            res.send('欢迎您,老朋友,再次光临,余额为'+req.session.point);
        }
    }else{
        req.session.point = 100;
        res.send('欢迎您,新朋友,送您会员卡,余额为'+req.session.point);
    }
});

app.listen(8090);

cookie签名:

cookie 虽然很方便,但是使用 cookie 有一个很大的弊端,cookie 中的所有数据在客户端就可以被修改,数据非常容易被伪造,那么为了数据不被篡改,我们对cookie进行签名, 签名的作用是让服务端知道cookie有没有被修改

const express = require('express');
const cookieParser = require('cookie-parser');

//随机生成的字符串
var signStr = 'xadsafeowirw';

var app = express();

//需要将密匙传给cookieParser, 在接收数据的时候,进行解析。
app.use(cookieParser(signStr));

app.use('/', function (req, res) {
    //将密匙字符串赋值给req.secret,可以省略,在上面cookieparser()时会自动对secret赋值
    req.secret=signStr;

    //返回给浏览器的cookie, 这就是传说中的种cookie了
    //如果需要开启签名,第三个参数对象signed 设置为true.
    //由于cookie的大小限制4k,而签名后的cookie体积会增加,所以重要的cookie才签名
    res.cookie('cookiename', 'liwen', {signed: true, maxAge: 30*1000})

    //有没有签名的cookie,获取方式不一样。
    console.log('无签名', req.cookies);    // 无签名的cookie获取方式
    console.log('带签名',req.signedCookies);  // 带签名的cookie获取方式
    res.send('ok')
})
app.listen(8090);

个人学习笔记,如有错误或不准确之处,请大神指出,感谢~

文档参考:
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值