一个Login页面全面了解session与cookie
Posted moran1992
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一个Login页面全面了解session与cookie相关的知识,希望对你有一定的参考价值。
- 背景
做了四年的前端开发,对外一直说自己是web开发,那么身为一个web开发怎能不知道session与cookie以及其管理方式呢~
Login涉及技术栈:Nodejs,MongoDB,Express以及html,css,js
了解session与cookie之前首先要知道什么是http协议,为什么会出现session与cookie,可以参考很久之前总结的(戳我:session与cookie)。
- http协议:
http即超文本传输协议(万维网定义的),一种基于浏览器请求与服务器响应的链接,它是一个很纯粹的传输协议。http协议主要的特征就是它是一种无状态的协议(只针对cookie与session问题),在客户端连续向服务器发送请求的时候,每次请求的过程中只要数据交换完毕,服务器与客户端就会断开连接,再次请求的时候会重新连接客户端与服务器,这样服务器记录上次的对话,那么问题来了,如何让服务器知道是哪个客户端向自己发出的请求呢,这个时候cookie就诞生了~
- 什么是cookie
cookie是一小段文本信息,这段小文本信息由服务器首次响应客户端时发送的,在客户端向服务器首次发送请求的时候,服务器会判断是否要记录客户端的身份,如果需要,此时就会在响应中(response)给客户端发送一个cookie,该cookie文本信息保存在http的报头里,当浏览器会将cookie保存起来,当该浏览器再次发送请求时会携带cookie,服务器检查cookie来识别浏览器请求,这里cookie的特征就不在说明了。下面我们上代码!
页面代码:
<!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <script type="text/javascript" src="jquery-3.3.1.min.js"></script> <script type="text/javascript" src=‘test.js‘></script> </head> <body> <section> <h3>Register</h3> <div> <label style="display:inline-block; width: 100px;" id="register-user-name-label" htmlfor="register-user-name-input">register:</label> <input style="display:inline-block; width: 200px;" id="register-user-name-input" type="text" /> </div> <div> <label style="display:inline-block; width: 100px;" id="register-password-label" htmlfor="register-password-input">pasword:</label> <input style="display:inline-block; width: 200px;" id="register-password-input" type="text" /> </div> <button id="register" type="button">Register</button> </section> <section> <h3>Login</h3> <div> <label style="display:inline-block; width: 100px;" id="user-name-label" htmlfor="user-name-input">login name:</label> <input style="display:inline-block; width: 200px;" id="user-name-input" type="text" /> </div> <div> <label style="display:inline-block; width: 100px;" id="password-label" htmlfor="password-input">pasword:</label> <input style="display:inline-block; width: 200px;" id="password-input" type="text" /> </div> <button id="login" type="button">Login</button> </section> <script type="text/javascript" src=‘test.js‘></script> </body> </html>
很简单,一个注册按钮一个登陆按钮(ps:代码冗余请忽视,就是为了做个demo用)。
首先注册一个user:
注册user之后我们查看db
然后我们用这个user进行登陆操作,重点来啦~
首先刷新下页面,调用获取user方法,看下效果
代码如下:
app.get(‘/userInfo‘, function (req, res) { //cookie if (req.cookies.userInfo) { console.log(‘login successfully‘) } else { console.log(‘session timeout.‘); } res.status(200).json(req.cookies.userInfo); //session // if (req.session.userInfo) console.log(‘login successfully‘); // else console.log(‘session timeout.‘); })
好了先mark下,回头再来做对比,下面执行login操作,这里要上代码了。
首先引入一个中间件:
var cookie = require(‘cookie-parser‘);
使用它:
app.use(cookie(‘express_cookie‘)); //cookie app.post(‘/login‘, function (req, res) { User.findOne({ username: req.body.username }).then(function (userInfo) { if (!userInfo) { console.log(‘user is not exist.‘); return; } var data = {}; data[‘username‘] = userInfo.username; data[‘password‘] = userInfo.password; res.cookie(‘username‘, JSON.stringify(data), { maxAge: 900000, httpOnly: true }); res.status(200).json(data); }) .catch(function (e) { console.log(e); }) })
这里我们可以设置cookie的httpOnly属性,最大生命周期,等等,然后我们先在db内查询当前登录user,如果已经注册过,我们获取user信息并存入cookie中。这时候看下前端的响应有什么不同。
可以看见,服务器颁发的cookie在响应的header中的Set-Cookie中。似不似发现不同了。这时候我们在刷新下页面调用userInfo方法看下效果。
咦,我们发现这次的请求里面居然有cookie了,就这么神奇(Ps:我们要相信科学!)。
debug下看看
服务器端有我们想要的cookie信息了。这样服务器就可以根据cookie知道了我们每一次的请求是不是同一个人了。
总结:首先cookie是服务器颁发的,然后随着响应返回给客户端也就是我们的浏览器,浏览器保存cookie,每一次发送请求都会带着这个cookie来让服务器知道,嗯我就是上次的那个人,到这里对cookie是不是多少了解了一些呢~
好了,那么现在很多浏览器都是禁用cookie的,原因是啥呢~,由于cookie是可以被获取的以及cookie是可以修改的,这时候引出了web安全方面的姿势,跨站脚本攻击以及跨站协议伪造,可以参考我之前写的关于XSS攻击(戳我:什么是XSS以及CFRS),那么如果cookie禁用了我们该怎么办呢?这时候session就诞生了。
- 何为session:
session本省并不存在,只是一个概念,session是服务器用来记录客户端状态的机制,不同于cookie保存在浏览器中,session是保存在服务器上的,服务器会根据cookie生成一个session id存在服务器上,当请求再次抵达服务器时,服务器发出响应时会将session id 存在cookie内一同反回给浏览器,这就是session。session具体哪些特点这里就不写啦,话不多说,上代码。
首先引入一个中间件:
var session = require(‘express-session‘);
使用它
app.use(cookie(‘express_cookie‘)); app.use(session({ secret: ‘express_cookie‘, resave: false, saveUninitialized: true, cookie: { maxAge: 60 * 1000 * 30 }, rolling: true, })); app.post(‘/login‘, function (req, res) { User.findOne({ username: req.body.username }).then(function (userInfo) { if (!userInfo) { console.log(‘user is not exist.‘); return; } var data = {}; data[‘username‘] = userInfo.username; data[‘password‘] = userInfo.password; req.session.userInfo = data; res.status(200).json(data); }) .catch(function (e) { console.log(e); }) })
现在我们登录一下看下效果:
会发现,多了一个Cookie,而且Cookie里面多了一个sid,不用联想了,这就是sessionId,这时候我们在刷新一下页面看下userInfo变成啥样了呢?
可以清晰的看到再次请求的时候,sessionId会装在Cookie中,然后发送给服务器,这时候服务器就知道了,咦,原来是上个人。这就是session。
由于现在服务器session存入的方式我们采用了服务器自带的内存,也叫session memory。如果server挂了怎么办呢,挂掉了内存就释放了啊,session就没了啊。这个时候就引出了另外一个问题,session的可持续化。
- session的可持续化
session的可持续化方式简单的理解就是让session可以在生命周期内一直存在,可以把session存入db中,可以是MongoDB,可以是redis,上代码,我们这里用MongoDB吧,个人比较喜爱。
引入中间件:
var MongoStore = require(‘connect-mongo‘)(session);
app.use(cookie(‘express_cookie‘)); app.use(session({ secret: ‘express_cookie‘, resave: false, saveUninitialized: true, cookie: { maxAge: 60 * 1000 * 30 }, rolling: true, store: new MongoStore({ url: ‘mongodb://127.0.0.1:27017/demo‘, collection: ‘sessions‘ }) })); app.post(‘/login‘, function (req, res) { User.findOne({ username: req.body.username }).then(function (userInfo) { if (!userInfo) { console.log(‘user is not exist.‘); return; } var data = {}; data[‘username‘] = userInfo.username; data[‘password‘] = userInfo.password; req.session.userInfo = data; res.status(200).json(data); }) .catch(function (e) { console.log(e); }) })
http请求与响应部分我们就不看了,直接看server跟DB。
server中我们将userInfo放入session中
var data = {}; data[‘username‘] = userInfo.username; data[‘password‘] = userInfo.password; req.session.userInfo = data;
查看DB
咦,一条session就在DB中诞生了,这里要注意的是,session不是设置的时候就会存入DB中的,包括内存等等,而且响应成功的时候才会存入,一定要注意,不然坑的就是你。
然后刷新页面看下效果。
似不似,session中就有了user信息。好了到这里关于session持久化的问题也解决了。
登出功能就很简单了,销毁session就ok了,代码如下:
app.get("/loginOut",function(req,res){ req.session.destroy(function(err){ console.log(err); }) res.send(‘退出登录成功‘); });
Redis方式:
中间件以及使用:
var RedisStrore = require(‘connect-redis‘)(session); app.use(session({ secret: ‘express_cookie‘, resave: false, saveUninitialized: true, cookie: { maxAge: 60 * 1000 * 30 }, rolling: true, store: new RedisStrore({}) }));
总结:第一次登陆请求的时候,服务器会颁发一个sessionId,响应的时候将sessionId放入cookie中返回给浏览器,此时session已存入DB中,当再次请求的时候携带着sessionId进入服务器中,获取session信息,服务器还是会记得我。
时间不早了。在这块的知识还涉及什么时候token,token认证方式,以及什么是jwt。以后有时间会继续更新的。
代码地址:https://github.com/Dqhan/Login
大半夜的,写个博客不容易,请博客园管理员高抬贵手,让我留在首页吧。
以上是关于一个Login页面全面了解session与cookie的主要内容,如果未能解决你的问题,请参考以下文章