前后端的身份认证
1 web开发模式
①前后端分离web开发模式:
依赖ajax的广泛应用,后端仅负责接口,
有点:开发体验好,用户体验好,减轻了服务器端的渲染压力
缺点:不利于seo , React 的ssr技术可以解决。
②服务端渲染的web开发模式:服务器动态生成页面,发送给客户端带有数据,客户端不需要ajax 。有利于seo,不利于提高开发效率,同时占用服务器资源多。
2 如何选择web开发模式
①以业务场景作为选择开发模式的标准
②同一个项目中可以同时使用两种开发模式,如首屏服务器端渲染+其他页面前后端分离的开发模式
3 身份认证 Authentication
通过一定的手段,完成对身份的确认。日常生活中如高铁验票,支付宝或微信支付密码等
web开发中手机验证码、邮箱密码、二维码登录等。
3.1不同开发模式下的身份认证
①服务器端渲染,用Session
②前后端分离,用JWT认证
3.1.1 Session认证
HTTP 协议的无状态性,每次HTTP请求独立,服务器不会主动保留每次HTTP请求的状态。
突破HTTP无状态:与生活中出示VIP卡,享受VIP服务类似。服务器端给客户端一个登录成功后的登录标识(Cookie),这样就可以标识客服端,cookie存储再浏览器中,不超过4KB,名称Name、值Value、有效期、安全性、使用范围等组成。以键值对的形式存储。
Cookie是独立的,不同域名的cookie不能交叉使用。
自动发送
有期限
4KB限制
Cookie不具有安全性,重要信息不要存到Cookie中
提高身份认证的安全性,使用Seesion
Seesion的工作原理
客户的重要信息存在于服务器端
express中使用Session认证
npm install express-session
const session = require('express-session')
app.use(session({
secret:'keyboard cat', //任意字符串,随便填写
resave:false, //固定
saveUninitiaslized:true //固定
})) //注册全局案例
先配置express-session ,之后通过req.session来访问和使用session对象
app.post('/api/login',(req,res)=>{
if(req.body.username !=== 'admin' || req.body.password!=== '000000'){
return res.send({status:1,msg:'登录失败'}}
req.session.user=req.body //将用户的信息存储到session中
req.session.islogin = true //将用户的登录状态存储到session中
res.send({status:0,msg:'登录成功'})
})
从session中取数据
req.session获取之前存储的数据
app.get('/api/username',(req.res) = >{
if(!req.session.islogin) {
return res.send({status:1,msg:'fail'})
}
res.send({
status:0,msg:'success',
username:req.session.user.username
})
})
清空session
调用req.session.destroy() 函数,一般是客户推出登录的时候使用
app.post('/api/logout',(req,res)=>{
req.session.destroy()
res.send({
status:0,
msg:'退出登录成功'
})
}) //仅会销毁当前用户的session
3.1.2 JWT认证机制
JWT 在跨域的情况下,推荐使用JSON Web Token
工作原理:客户端提交账号、密码,服务器端通过认证后,加密生成Token字符串,客户端再次发起请求时,将Token发送给服务器,服务器把Token字符串还原成用户的信息对象,根据身份响应内容。
核心:服务器生成Token,发送给客户端,Token保存在客户端。
JWT 组成:Header、Payload、Signature
字符串的第一个点号是Header,第一个点号与第二个点号之间是Payload,第二个点号之后是Signature
Payload是真正的用户信息,Header与Signature是安全相关部分。
JWT使用方式:浏览器将JWT存储在localStorage或sessionStorage中,推荐做法
Authorization:Bearer <token>
3.1.2.1 安装JWT相关的包
npm install jsonwebtoken express-jwt
jsonwebtoken :生成JWT字符串
express-jwt :将jwt字符串还原为json
//导入包
const jwt = require('jsonwebtoken')
const expressJWT = require('express-jwt')
3.1.2.2 定义密钥
密钥:加密与解密 jwt字串,越复杂越安全
const secretKey = 'itheima No1 ^_^'
3.1.2.3 生成jwt字串
使用jsonwebtoken的sign()方法,生成JWT字符串,三个参数,用户信息,加密密钥,配置对象,千万不要将密码加密到字符串中
const tokenStr=jwt.sign({
username:userinfo.username},secretKey,{expiresIn:'30s'}
) // 生成token字符串
3.1.2.4 还原JWT为json
请求头中的Authorization字段中Token发送给服务器,服务器通过express-jwt还原json
//app.use() 注册中间件;expressJWT({secret:secretKey}) 解析;unless({path:[/^\/api\//]})指定哪些接口不需要访问权限
实例: app.use(expressJWT({secret:secretKey}).unless({path:[/^\/api\//]})) //unless 中的正则可以改,其他基本是固定写法。配置成功后,会自动将用户信息挂载到req.user中
3.1.2.5 使用req.user获取用户信息
示例:app.get('/admin/getinfo',function(req,res) {
console.log(req.user)
res.send({
status:200,
message:'获取用户信息成功!'
data:req.user
})
})
3.1.2.6 捕获JWT失败后产生的错误
app.use((err,req,res,next) = >{
if( err.name=== 'UnauthorizedError'){
return res.send({status:401,message:'无效的token'})
}
res.send({status:500,message:'未知错误'})
})