HTTP 是一种没有状态的协议,也就是它并不知道是谁访问。客户端用户名密码通过了身份验证,不过下回这个客户端再发送请求时候,还得再验证
1、客户端用户名跟密码请求登录
2、服务端收到请求,去库验证用户名与密码
3、验证成功后,服务端种一个cookie或发一个字符到客户端,同时服务器保留一份session
4、客户端收到 响应 以后可以把收到的字符存到cookie
5、客户端每次向服务端请求资源的cookie会自动携带
6、服务端收到请求,然后去验证cookie和session,如果验证成功,就向客户端返回请求的库数据
Session存储位置: 服务器内存,磁盘,或者数据库里
Session存储内容: id,存储时间,用户名等说明一下登录的用户是谁
客户端携带 : cookie自动带,localStorage手动带
前端种:
cookie/localstorage
后端种:
服务器给浏览器种cookie: cookie-parser
服务器给浏览器种cookie的同时在服务器上生成seesion: cookie-session
安装引入
let cookieSession = require('cookie-session')
app.use(cookieSession({
name:'保存到服务器的session的名字',
keys:[必传参数,代表加密层级],
maxAge:1000 //保留cookie的时间
}))
req.session.key=value
req.session.key 返回true
delete req.session.key
req.session.key = undefined
具体代码如下:
let express = require("express")
let cookieSession = require("cookie-session")
// 搭建服务器
let app = express()
// 静态资源托管
app.use(express.static("./public"))
// 监听端口
app.listen(3000)
// 使用中间件cookieSession
app.use(cookieSession({
keys: ["aa", "bb", "cc"],//加密层级
maxAge:1000*30 //cookie的失效时间
}))
// 验证用户身份
app.get("/api/login", (req, res) => {
// 1.验证客户端传递来的用户名密码和数据库是否一样
// 给用户端中cookie,并且同时和服务端留一份session
// console.log(req.session);
req.session.nz = "userId"
// 后端种完后给后端返回数据
res.send({
err: 0,
msg: "登录成功!",
data: {
username: "张三丰"
}
})
})
// 自动登录功能
app.get("/api/user", (req, res) => {
//读cookie对比session
//如果前端传递来的cookie是有效的,那么req.session.nz1906的值就是“userId"
//如果前端传递来的cookie失效了,那么req.session.nz1906的值就是undefined
let pass = req.session.nz //如果用户登录了,那么pass="userId",如果用户cookie失效或者没有,那么返回null
if(pass){
//用户身份一直存在的,取库数据,并且返回
res.send({
erro:0,
data:"/api/user的数据!!!"
})
}else{
res.send({
err:1,
data:"请先登录账号或登录过期"
})
}
res.end()
})
// 注销登录
app.get("/api/logout",(req,res)=>{
//删除服务端session和客户端的cookie
req.session.nz = undefined
res.end()
})
在服务端不需要存储用户的登录记录,全部发给客户端有客户端自己存(cookie,local)
1、客户端使用用户名跟密码请求登录
2、服务端收到请求,去验证用户名与密码
3、验证成功后,服务端会签发一个 Token(加了密的字符串),再把这个 Token 发送给客户端
4、客户端收到 Token 以后可以把它存储起来,比如放在 Cookie 里或者 Local Storage 里
5、客户端每次向服务端请求资源的时候需要带着服务端签发的 Token
6、服务端收到请求,然后去验证客户端请求里面带着的 Token,如果验证成功,就向客户端返回请求的数据
jsonwebtoken的安装引入
let jwt = require('jsonwebtoken')
let token = jwt.sign(payload, secretOrPrivateKey, [options, callback])
校验token
jwt.verify(token, secretOrPublicKey, [options, callback])
由客户端,负责删除
token讲解具体代码如下
let express = require("express")
let app = express()
// 插入中间件
let bodyParser = require("body-parser")
// 引入jsonwebtoken模块
let jwt = require("jsonwebtoken")
app.listen(3000, () => console.log("3000端口正在接听。。。"))
// 使用中间件
app.use(bodyParser())
// 请求登录,服务端生成token令牌
app.get("/api/login", (req, res) => {
// 获取前端传过来的username,password进行数据库的验证
// 生成token令牌
let token = jwt.sign({
username: req.query.username
}, "nz",{expiresIn:60}) //expiresIn cookie失效时间,按照秒计算
// 将token和库信息返回前端
res.send({
err: 0,
msg: "登录成功",
data: "数据库",
token
})
})
// 验证toknn
app.get("/api/user", (req, res) => {
// 获取客户端传递的token
// 数据库放在 地址栏上面 || 非地址栏上面 || 请求头上面
let token = req.query.token || req.body.token || req.headers.token;
// 验证token
jwt.verify(token, "nz", (err, decode) => {
// console.log("err",err); //null代表没有报错
console.log("decode",decode);
if (err) {
//报错说明用户信息验证失败
res.send({
err: 1,
msg: "登录失败,token失效"
})
} else {
// 验证成功
// 数据返回给前端
res.send({
err: 0,
msg: "登录成功",
data: "数据库"
})
}
})
})
session | token | |
---|---|---|
服务端保存用户信息 | √ | × |
避免CSRF攻击 | × | √ |
安装性 | 一般 | 高 |
多服务器粘性问题 | 存在 | 不存在 |
多服务器粘性问题
当在应用中进行 session的读,写或者删除操作时,会有一个文件操作发生在操作系统的temp 文件夹下,至少在第一次时。假设有多台服务器并且 session 在第一台服务上创建。当你再次发送请求并且这个请求落在另一台服务器上,session 信息并不存在并且会获得一个“未认证”的响应。我知道,你可以通过一个粘性 session 解决这个问题。然而,在基于 token 的认证中,这个问题很自然就被解决了。没有粘性 session 的问题,因为在每个发送到服务器的请求中这个请求的 token 都会被拦截
家中逆战,无畏疫情,武汉加油,中国加油,人类必胜!!!