身份认证
服务端渲染使用Session认证机制
Cookie
1 键值对,值不超过4kb
2 不同域名下的cookie各自独立
3 有过期时限
4 每次客户发起请求会把当前域名下所有未过期的cookie一同发给服务器
作用
客户端第一次请求服务器时,服务器会通过响应头形式向客户端发送一个身份认证的Cookie,客户端会自动把cookie保存在浏览器中,之后客户端再每次请求服务时,浏览器会自动把身份认证相关cookie以请求头形式发给服务器,服务器进行验证身份,发送身份对应的内容给客户端
提高身份认证安全性--Session认证机制
cookie不具有安全性,不建议把重要隐私数据通过cookie发送
安装express-session中间件
npm i express-session
实例:
// 导入express
const express = require('express')
// 创建express服务器实例
const app = express()
//导入xpress-session中间件
var session = require('express-session')
// 配置session中间件
app.use(session({
secret: 'my secrect', //可以为任意值
resave: false, //固定写法
saveUninitialized: true //固定写法
}))
// 托管静态页面
app.use(express.static('./pages'))
app.use(express.urlencoded({ extended: false }))
// 登录接口——session存数据
app.post('/api/login', (req, res) => {
if (req.body.username !== 'admin' || req.body.password != '000000') {
return res.send({
status: 1,
msg: '账号密码错误,登陆失败!'
})
}
// 把登陆成功后的用户信息存到session中
req.session.user = req.body //存储用户登录信息
req.session.isLogin = true //存储登陆状态
res.send({
status: 0,
msg: '登录成功'
})
})
// 获取用户姓名接口——session取数据
app.get('/api/username', (req, res) => {
//判断是否登录
if (!req.session.isLogin) {
return res.send({
status: 1,
msg: '获取失败'
})
}
res.send({
status: 0,
msg: '获取成功',
username: req.session.user.username
})
})
//退出登录——清空session
app.post('/api/logout', (req, res) => {
req.session.destroy()
res.send({
status: 0,
msg: '退出登录成功'
})
})
app.listen(8081, () => {
console.log('http://127.0.0.1:8081')
})
局限性
需要配合cookie实现,cookie不支持跨域访问,所以涉及到跨域需要做很多额外配置才能实现跨域session认证
前后端分离推荐使用JWT认证机制(token)
header.payload.signature payload:加密后的用户信息 header、signature:安全性相关部分,保证token安全性
推荐把JWT放在http请求头的Authorization字段中 Authorization: Bearer
安装jwt相关包
jsonwebtoken:生成jwt字符串
express-jwt:解析还原jwt字符串(踩坑:安装5.3.3,否则会报错)
命令:npm i jsonwebtoken express-jwt
实例
// 导入express
const express = require('express')
// 创建express服务器实例
const app = express()
//导入jwt中间件
var jwt = require('jsonwebtoken')
var expressJWT = require('express-jwt')
// 托管静态页面
// app.use(express.static('./pages'))
// 解决跨域
const cors = require('cors')
app.use(cors())
const parser = require('body-parser')
app.use(parser.urlencoded({ extended: false }))
// 定义secret密钥 本质就是定义一个字符串
const secretKey = 'my test key'
// 配置解析jwt还原成json
// 解析token:expressJWT({secret:secretKey})
// .unless({path:[/^\/api\//]}) 用来指定哪些接口不需要访问权限
app.use(expressJWT({ secret: secretKey }).unless({ path: [/^\/api\//] }))
// 登录接口——生成jwt字符串
app.post('/api/login', (req, res) => {
const userinfo = req.body
if (userinfo.username !== 'admin' || userinfo.password != '000000') {
return res.send({
status: 400,
msg: '账号密码错误,登陆失败!'
})
}
// 登陆成功生成jwt字符串,通过token传给用户
const tokenStr = jwt.sign({ username: userinfo.username }, secretKey, { expiresIn: '30s' })
res.send({
status: 0,
msg: '登录成功',
// 调用jwt.sign(生成jwt字符串,三个参数:用户信息对象,加密密钥,配置对象(配置token有效期 30秒)
token: tokenStr
})
})
// 获取用户信息接口——还原jwt
app.get('/admin/getinfo', (req, res) => {
// 配置成功express-jwt中间件会把解析出来的用户信息,挂载到req.user属性上
// postman测试时发送请求头Authorization: Bearer <token>
console.log(req.user)
res.send({
status: 0,
msg: '获取成功',
data: req.user
})
})
// 使用全局错误处理中间件,捕获JWT失败产生的错误
app.use((err, req, res, next) => {
// UnauthorizedError:token解析失败错误
if (err.name === 'UnauthorizedError') {
return res.send({
status: 401,
message: '无效的token'
})
}
res.send({
status: 500,
message: '未知的错误'
})
})
app.listen(8081, () => {
console.log('http://127.0.0.1:8081')
})