
login.jpg
前面我们讲了数据库的操作,已经可以轻松实现增删改查,接下来,就是服务端开发中的一个重点,就是登录验证,本篇文章由浅入深介绍登录验证中cookie,session,redis的作用。开始吧
登录
cookie
首先我么需要了解cookie。以如何查看cookie,客户端如何操作cookie
- 存储在浏览器中的一段字符串(5kb)
- 跨域不共享
- 可以发送给server端
server端操作cookie
- 查看
- 修改
- 登录验证
- 解析cookie
//解析cookie
req.cookie = {}
const cookieString = req.headers.cookie || ''
cookieString.split(';').forEach(item => {
if(!item) {
return
}
const arr = item.split('=')
const key = arr[0].trim()//trim()去掉前后空格
const val = arr[1].trim()
req.cookie[key] = val
})
上面的代码将‘k1=v1; k2=v2;’这样的字符串变为对象,我们可以直接从req.cookie中获取。
- 登录时设置
cookie
//定义过期时间函数
const getCookieExpires = () => {
const d = new Date()
d.setTime(d.getTime() + (24 * 60 * 60 * 1000))
return d.toGMTString()
}
res.setHeader('Set-Cookie', `username=${data.username}; path=/; httpOnly; expires=${getCookieExpires()}`)
需要注意:
-
path为cookie的生效路径,我们一般要设置为项目的根目录,才能在项目中所有路径中生效; -
httpOnly为限制只能在服务端修改cookie,防止用户客户端修改cookie; -
expires为设置过期时间
如上,我们已经可以利用cookie来做登录验证,但上面的方法还是存在着一些问题,他会把一些关键信息暴露在cookie中,在客户端可以被查看,这是不安全的,所以,我们下面将使用session来讲重要的信息存储在session中,因为session是存在内存中的,其容量也比cookie大的多,所以使用session将是一个很棒的解决方案
Session
使用session后,我们的登录信息的处理机制要变一变,待会会做出下面的修改
// 解析session
let needSetCookie = false
let userId = req.cookie.userid
if (userId) {
if (!SESSION_DATA[userId]) {
SESSION_DATA[userId] = {}
}
} else {
needSetCookie = true
userId = `${Date.now()}_${Math.random()}`
SESSION_DATA[userId] = {}
}
req.session = SESSION_DATA[userId]
我们会根据当前访问接口中,有无需要设置cookie来做出判断
userResult.then(userData => {
if(needSetCookie) {
res.setHeader('Set-Cookie', `userid=${userId}; path=/; httpOnly; expires=${getCookieExpires()}`)
}
res.end(
JSON.stringify(userData)
)
})
这样,我们在controller中就不需要设置cookie了,只需要在登录接口中,设置session即可
if(data.username) {
// 设置session
req.session.username = data.username
req.session.realname = data.realname
return new SuccessModel()
}
接下来捋一捋代码吧,看看用session怎么做登录验证
上面我们使用了session做登录验证,并把一些重要信息存于内存中但这样会面临如下问题
- session存储于一个js变量中。
- 数据量大,内存爆了怎么办?
- 线上是多进程的,且进程间内存不共享。我们的session将不能保证准确访问
于是,我们将引入下一个概念--Redis
Radis
- web Server中最常用的内存数据库
- 相比于mysql,访问速度更快(因为mysql基于硬盘,redis基于内存)
- 成本高,可存储的数据量 小
在项目中,我们采用mysql和redis结合使用的方式
- 将webServer和redis拆分为两个单独的服务
- 双方都是独立的,都是可扩展的
为什么Session适合存储于redis中?
- session访问频繁,对性能要求极高
- session可以不用考虑断点丢失的问题(这是内存的硬伤)
- session中数据量不会很大(相比于mysql中的数据)
为什么网站数据不适合使用redis?
- 操作频率不是太高(相对于session操作)
- 断电不能丢失,必须保留
- 数据量太大,内存成本太高