身份认证,也叫“鉴权”。指通过一定的手段去确认身份。

对于服务端渲染前后端分离这两种开发模式来说,分别有着不同的身份认证方案:

  1. 服务端渲染推荐使用session认证机制
  2. 前后端分离推荐使用JWT认证机制

OpenResty 身份认证前置服务 前后端身份认证_服务器

OpenResty 身份认证前置服务 前后端身份认证_前端_02

一、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密钥

用于加密和解密的密钥

  1. 当生成JWT字符串的时候,需要使用secret密钥对用户的信息进行加密,最终得到加密好的JWT字符串。
  2. 当把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: '未知错误' })
})