发现只有在写博客的时候,才会认真地去学习。总结一下我在学习、写前后端项目中的一些有关身份验证的心得体会。
因为HTTP是无状态的,如何保证用户和用户之间的操作隔离开来,如何保证有些接口、页面只有某些用户才能访问。一般通过下面的方式实现:
1.cookie方案
原理
这种方式依赖没用禁用cookie浏览器环境。
step1:客户端请求登陆接口,服务端返回200状态码同时把cookie给客户端。
step2:客户端在需要身份验证的接口上带上cookie。
step3:服务端把cookie取出、解析后就可以知道身份了。
那session(会话)又是什么?session不是一个实体,而是基于cookie来维持会话状态的一种技术。有些敏感信息存储在客户端导致不安全,所以服务端在创建session的时候生成一个session_id通过cookie传给客户端。而服务端维持一个 session_id -> session 类似的哈希结构。
一般来说session是在内存中的,但是通常会把这个哈希结构用KV(键值对)数据库来存储,这样做的好处是方便管理,而且在分布式的环境下也可以。
服务端大致实现思路:
const http = require('http')
const server = http.createServer((req, res) => {
if (req.url === '/login'){
// 从数据库中验证账号密码正确(略)
// 保存下面这个SESSION_ID(略)
// 设置响应头
res.writeHead(200, {
'Content-Type': 'application/json',
'Set-Cookie': 'SESSION_ID=abcdefg; HttpOnly;'
})
// 返回响应
res.write(JSON.stringify({
code: 200,
msg: 'OK'
}))
res.end()
}
// 匹配其他路由
else {
if (req.headers.cookie && isValid(req.headers.cookie)){
// 解析cookie并验证,验证通过做一些事情
// 验证失败则返回code 401
res.write('OK')
res.end()
}
}
})
server.listen(3000)
前端需要注意:使用fetch时默认不携带cookie,需要手动设置。在XMLHttpRequest中也是。
// Fetch
fetch({
//cookie既可以同域发送,也可以跨域发送
credentials: 'include'
})
// XMLHttpRequest
xhr.withCredentials = true
安全
首先,没用绝对的安全。只能通过一些手段来提高安全性。
1.在set-cookie的时候使用HttpOnly。这样可以防止客户端通过JS来获取cookie,在一些XSS攻击中可能会导致cookie泄漏。
2.HTTPS。在传输过程中cookie不会以明文的方式传递,就算被第三方截取,也是加密过的。
3.服务端的session过期机制。
Token方案
在一些非浏览器环境下(当然浏览器环境也可以使用该方案),如微信小程序、APP中等前端如何和后端通信。其实原理和上面说的是一样的。
原理
step1:客户端请求登陆接口,服务端返回Token,且客户端手动将Token保存。
step2:客户端发起请求的时候将Token带上。
step3:服务端解析Token。
不同就在于需要手动去存储这个凭证。
安全
1.Token设置过期时间,增加刷新机制。
2.HTTPS。
JWT
JWT(JSON Web Token),我过去对JWT的理解是错误的。
参考:停止使用 JWT 认证。JWT适合用于一次性登陆的场景。
优点是服务端消耗更少的资源(不用去保存状态)。
一般jwt保存在localStorage里面,泄漏了jwt同样会导致身份被盗用。可以通过在payload里面设置过期时间来避免泄漏后造成的风险。所以“更安全”不成立。