不同开发模式下的身份认证:
服务器端渲染推荐使用Session认证机制
Cookie
cookie是什么
cookie是存储在用户浏览器中的一段不超过4KB的字符串。他是有一个名称、一个值、和其他几个用于控制cookie有效期、安全性、使用范围的可选属性组成。
不同域名下的cookie各自独立,每当客户发起请求时,会自动把当前域名下所有未过期的cookie一同发送到服务器。
特性:自动发送、域名独立、过期时限、4KB限制
cookie在身份认证中的作用
客户端第一次请求服务器的时候,服务器通过响应头的形式,向客户端发送一个身份认证的cookie,客户端会自动将cookie保存在浏览器中。
随后,当客户端浏览器每次请求服务器的时候,浏览器会自动将身份认证相关的cookie,通过请求头的形式发送给服务器,服务器即可验明客户端的身份。
cookie不具有安全性
由于cookie是存储在浏览器中的,而且浏览器也提供了读写cookie的API,因此cookie很容易被伪造,不具有安全性。因此不建议服务器将重要的隐私数据,通过cookie的形式发送给浏览器。
提高身份认证的安全性
"会员卡+刷卡认证"的设计理念,就是session认证机制的精髓
Session
session工作原理
1、用户第一次登录浏览器客户端时填写账号密码登录,成功后将用户的基础信息存储在服务器的内存中,同时服务器生成对应的cookie字符串将cookie响应给浏览器客户端,浏览器自动把cookie存储在当下域名。
2、当用户再次发起请求想要登录页面时,就不用再次输入账号和密码,而是客户端浏览器通过请求头,自动把当前域名下所有可用cookie发送给服务器,服务器根据请求头中携带的cookie从内存中查找对应的用户信息,如果查找到对应的信息则认证成功,返回给用户登录后的页面。可以通过这种方式免去用户经常登录
使用 express-session中间件
1、安装后,通过app.use()来注册session中间件,示例代码:
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
var session = require('express-session')
app.use(session({
secret:'keybord cat',//secret的值可以为任意字符串
resave:false,//固定写法
saveUninitialized:true//固定写法
}))
2、往session存数据
通过req.session来访问和使用对象,从而存储用户关键信息
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
apiRouter.post("/api/login", (req, res) => {
req.session.user = req.body;//存储用户信息填到session
req.session.islogin= true;//存储登陆状态填到session
res.send({
status: 0, //状态 成功0 失败1
msg: "请求成功", //状态描述
});
});
3、从session取数据
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
apiRouter.get("/api/username", (req, res) => {
if(!req.session.islogin){
return res.send({status:1,msg:'fail'})
}
req.session.user = req.body;//存储用户信息填到session
req.session.islogin= true;//存储登陆状态填到session
res.send({
status: 0, //状态 成功0 失败1
msg: "get请求成功", //状态描述
username:req.session.user.username
});
});
4、清空session
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
apiRouter.post("/api/logout", (req, res) => {
req.session.destory()//清空
res.send({
status: 0, //状态 成功0 失败1
msg: "退出登录成功", //状态描述
});
});
前后端分离推荐使用JWT认证机制
Session局限性
session认证机制需要配合cookie才能实现,由于cookie默认不支持跨域访问,所以当涉及前端跨域请求后端接口的时候,需要做很多额外的配置才能实现跨域session认证。
注意:
当前端请求后端接口不存在跨域问题的时候推荐使用session身份认证机制
当前端需要跨域请求后端接口的时候,不推荐使用session身份认证机制,推荐使用JWT认证机制
什么是JWT
JWT是目前最流行的跨域认证解决方案
JWT工作原理
1、客户端浏览器登录时提交账号与密码,服务端验证通过后,将用户的信息对象经过加密之后生成token字符串,服务器将生成的token发送给客户端。
2、客户端将token存储到Localstorage或Sessionstorage,客户再次发起请求时,通过请求头的authorization字段将token发送给服务器。
3、服务器把token字符串还原成为用户的信息对象,用户身份认证成功后服务器针对当前用户生成特定响应内容。
组成部分
JWT通常由三部分组成,分别是Header头部、Payload有效荷载、signature签名。三者之间使用'.'分隔。
Payload部分才是真正的用户信息,它是用户信息经过加密之后生成的字符串。
Header、signature是安全性相关的部分只是为了保证token的安全性。
使用方式
客户端收到服务端返回的JWT之后,通常会将它存储在localstorage或sessionstorage中。
此后,客户端每次与服务器通信,都要带上这个GWT的字符串,从而进行身份认证。推荐的做法是把JWT放在HTTP的请求头authorization字段中,格式如下:
Authorization: Bearer <token>
Express中使用JWT
1、安装导入
npm install jsonwebtoken express-jwt
其中:jsonwebtoken用于生成JWT字符串,express-jwt用于将JWT字符串解析还原成JSON对象
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
const jwt = require('jsonwebtoken')
const expressjwt= require('express-jwt')
2、定义secret密钥
为了保证JWT字符串的安全性, 防止JWT字符串在网络传输过程中被别人破解, 我们需要专门定义一个用于加密和解密的secret密钥。
密钥的作用:
1.当生成JWT字符串的时候, 需要使用secret密钥对用户的信息进行加密, 最终得到加密好的JWT字符串。
2.当靶机WT字符串解析还原成JSON对象的时候需要使用secret密钥进行解密。
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
//定义一个scret,scret的本质是一个字符串
const secretKey = 'itheima No1 ^_^'
3、在登陆成功后生成jjwt字符串
调用jsonwebtoken包提供的sign()方法, 将用户的信息加密成JWT字符串响应给客户端:
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
//登录接口
app.post("/api/login", (req, res) => {
//。。。省略登陆失败的代码
res.send({
status: 200,
msg: "登录成功", //状态描述
//调用JWT , sign()生成JWT字符串, 三个参数分别是:用户信息对象、加密密钥、配置对象
token:jwt.sign({username:'zs',secretKey ,{expiresIn:'30s'}})//expiresIn:'30s'指时限30秒
});
});
4、将jwt字符串还原为json对象
客户端每次在访问那些有权限的接口时,都需要主动通过请求头中的authorization字段,将token字符串发送到服务器进行身份认证。
此时,服务器可以通过express-jwt这个中间件,自动将客户端发送过来的token解析还原成JSON对象:
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
//使用app.use()来注册中间件
app.use(expressjwt({secret:secretKey}).unless({path:[/^\/api\//]}))
//expressjwt({secret:secretKey})就是用来解析token的中间件
//unless({path:[/^\/api\//]用来指定哪些接口不需要访问权限
//^\/api\/正则表达式,表示必须以/api开头,如:/api/xxxxx...
5、捕获解析JWT失败后产生的错误
使用express-jwt解析token字符串时,如果客户端发过来的token字符串过期或不合法,影响项目正常运行。我们可以通过express的错误中间件,捕获这个错误并进行相关处理,示例代码:
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown
app.use(err,req,res,next) =>{
//token解析失败导致的错误
if(err.name === 'Unauthorization'){
return res.send({status:401,message:'无效的token'})
}
//其他元婴导致的错误
res.send({status:500,mesage:'未知错误'})
}