身份认证,也叫“鉴权”。指通过一定的手段去确认身份。
对于服务端渲染和前后端分离这两种开发模式来说,分别有着不同的身份认证方案:
- 服务端渲染推荐使用session认证机制
- 前后端分离推荐使用JWT认证机制
一、Session认证机制
1、HTTP协议的无状态性
了解HTTP协议的无状态性是进一步学习Session认证机制的必要前提。
HTTP协议的无状态性,指的是客户端的每次HTTP请求都是独立的,连续多个请求之间没有直接的关系,服务器不会主动保留每次HTTP请求的状态。
eg:超市收银员不知道客户是否是vip
2、突破HTTP协议无状态的限制
现实生活中的会员卡身份认证方式,在Web开发中的专业术语叫做Cookie
eg:超市可以给每个vip用户发放会员卡,通过会员卡辨别vip身份
3、什么是cookie
Cookie是存储在用户浏览器中的一段不超过4KB的字符串,由一个名称name、一个值value和其他几个用于控制cookie有效期、安全性、使用范围的可选属性组成。
不同域名下的cookie各自独立,每当客户端发起请求时,会自动把当前域名下所有未过期的cookie一同发送到服务端。
cookie的几大特性:
- 自动发送
- 域名独立
- 过期时限
- 4KB限制
4、cookie在身份认证中的作用
客户端第一次请求服务器的时候,服务器通过响应投的形式,向客户端发送一哥身份认证的cookie,客户端会自动将cookie保存在浏览器中。
随后,当客户端浏览器每次请求服务器的时候,浏览器会自动将身份认证相关的cookie,通过请求头的形式发送给服务器,服务器即可验明客户端的身份。
5、cookie不具有安全性
由于cookie是存储在浏览器中的,而且浏览器也提供了读写coolie的api,因此容易被伪造。所以不要用cookie存储用户的隐私。
eg:会员卡
6、提高身份认证的安全性
eg:会员卡+刷卡认证
7、在express中使用session认证
// 安装
npm install express-session
var session = require('express-session')
app.use(session({
secret: 'keyboard cat', // 值可以为任意的字符串
resave: false, // 固定写法
saveUninitialized: true // 固定写法
}))
// 在接口中使用req。session
req.session.userInfo = req.body
req.session.isLogin = true
// 清空session
req.session.destroy()
二、JWT认证机制
1、工作原理
JWT全称:JSON Web Token
JWT三大组成部分:Header.Payload(有效载荷).Signature
使用方式: 客户端收到服务端返回的JWT后,通常会存储在localstorage或sessionstorage中。此后,客户端每次与服务器通信,都要带上这个JWT的字符串,从而进行身份认证。推荐的做法是把JWT放在HTTP请求头的Authorization字段中,格式如下:
Authorization: Bearer <token>
2、在express中使用JWT
// jsonwebtoken用于生成jwt字符串,express-jwt用于将jwt字符串解析还原成json对象
// 安装
npm install jsonwebtoken express-jwt
var jwt = require('jsonwebtoken')
var expressJWT = require('express-jwt')
app.use(session({
secret: 'keyboard cat', // 值可以为任意的字符串
resave: false, // 固定写法
saveUninitialized: true // 固定写法
}))
3、定义secret密钥
用于加密和解密的密钥
- 当生成JWT字符串的时候,需要使用secret密钥对用户的信息进行加密,最终得到加密好的JWT字符串。
- 当把JWT字符串解析还原成JSON对象的时候,需要使用secret密钥进行解密。
const secretKey = 'keyboard cat ^-^'
4、生成JWT字符串
app.post({
...
// 登录成功后,调用jwt.sign()生成JWT对象,并通过token属性发送给客户端
res.send({
...
status: 200,
message: '登陆成功',
// 3个参数:用户信息对象,加密秘钥,配置对象
token:jwt.sign({ username:yq }, secretKey, { expiresIn: '30s' })
})
})
5、将JWT字符串还原成json对象
客户端每次在访问那些有权限的接口时,都需要主动通过请求头中的Authorization字段,将token字符串发送到服务端进行身份认证。此时,服务器可以通过express-jwt这个中间件,自动将客户端发送过来的Token解析还原成json对象:
// expressJWT({ secret: secretKey }) 解析token中间件
// unless({ path: [/^\/api\//] }) 用来指定哪些接口不需要访问权限
app.use(expressJWT({ secret: secretKey }).unless({ path: [/^\/api\//] }))
6、捕获解析JWT失败后产生的错误
当时用express-jwt解析token字符串时,如果客户端发送过来的token字符串过期或者不合法,会产生一个解析失败的错误,影响项目的正常运行。我们可以通过express的错误中渐渐,捕获错误。
app.use((err, req, res, next) => {
// token 解析失败导致的错误
if(err.name === 'UnauthorizedError') {
return res.send({ status: 401, message: '无效token' })
}
// 其他原因导致的错误
res.send({ status: 500, message: '未知错误' })
})