web开发模式
目前有两个主流:
- 服务端渲染
- 前后端分离
服务端渲染:服务器发给客户端html页面,在服务器端通过拼接,动态生成。所以客户端不需要使用ajax技术。
优点:前端耗时少,有利于seo
缺点:占用服务器资源,不利于前后分离,开发效率低
前后端分离:依赖于ajax
优点:开发体验好,用户体验好,减轻了服务端的渲染压力。
缺点:不利于网站的seo
身份认证
服务端渲染使用session认证机制
前后分离使用JWT认证机制
Session认证机制
http协议无状态性:就是发送多次请求,服务器不会保留上一次的状态。
现实生活中会员卡身份认证,在web中叫做Cookie,Cookie是存放浏览器的字符串,由名称,值等组成 用于控制Cookie有效期,安全性,使用范围的可选属性组成。session认证不适合跨域认证。
下面使用Session认证:
# 安装
yarn add express-session
// app.js
const express = require('express')
const cors = require('cors')
// 导入session
const session = require('express-session')
// 创建app
const app = express()
// 注册中间件
app.use(express.static('./pages'))
app.use(cors())
app.use(express.json())
app.use(express.urlencoded({ extended: false }))
// 使用session 固定写法
app.use(
session({
secret: 'zxc', // 任意字符 密钥
resave: false,
saveUninitialized: true
})
)
// 登录
app.post('/api/login', (req, res) => {
if (req.body.username !== 'admin' || req.body.password !== '000') {
return res.send({ status: 1, msg: '登陆失败' })
}
// 登陆成功后的用户信息 保存到session中
req.session.user = req.body //用户信息
req.session.islogin = true //登陆状态
res.send({
statu: 0,
msg:'登陆成功'
})
})
// 获取session中的数据
app.get('/api/username', (req, res) => {
if (!req.session.islogin) {
return res.send({ status: 1, meg: 'fail' })
}
res.send({ status: 0, data: req.session.username })
})
// 退出登录清空session
app.post('/api/logout', (req, res) => {
req.session.destroy() //只会清空当前用户的session
res.send({ status: 0, msg: '退出成功' })
})
app.listen(80, () => {
console.log('http://127.0.0.1')
})
JWT认证机制
jwt工作原理:客户端提交账户密码发送给服务端,服务端验证账号密码通过后会返回给客户端一个token字符串,客户端拿到之后进行本地存储。等再一次登陆时,直接使用本地存储的token字符串进行登录就实现了免密登录。
jwt字符串由 header payload signature组成,payload部分才是真正的用户信息,其他两部分只为了保证token的安全性。
下面是jwt的使用方式:
拿到token后,每次请求服务器都在请求头带上token字段,推荐做法:
// 设置请求头 Authorization字段
Authorization: Bearer <token>
安装
yarn add jsonwebtoken express-jwt
jsonwebtoken:可以生产token字段
express-jwt:用于将jwt字符串解析还原成json对象,当我们配置了之后,那么req.user就是存储的是当前解析token中的数据,就可以使用req.user获取。
// app.js
const express = require('express')
const jwt = require('jsonwebtoken')
const expressJWT = require('express-jwt')
const bodyParser = require('body-parser')
// 创建app
const app = express()
// 注册中间件
app.use(bodyParser.urlencoded({ extended: false }))
const secretKey = 'test-01' //定义secretKey密钥
// 解析token 需要secretKey密钥,algorithms为['HS256'] unless中的path可以指定不需要token验证的接口
app.use(
// 配置了express-jwt中间件 就可以把解析出来的用户信息挂载到 req.user上
expressJWT({ secret: secretKey, algorithms: ['HS256'] }).unless({
path: [/\/api\/login/]
})
)
// 登录接口
app.post('/api/login', (req, res) => {
const { username, password } = req.body
if (username !== 'admin' || password !== '000') {
return res.send({ status: 1, msg: '登陆失败' })
}
// jwt.sign() 生成token
// 参数一:用户信息对象
// 参数二:加密的密钥
// 参数三:配置对象,可以配置token有效期
// 千万不要把密码加密到字符串中,否则就危险了
const token = jwt.sign({ username }, secretKey, {
expiresIn: '30s'
})
res.send({
status: 200,
msg: '登陆成功',
token
})
})
// expressJWT 解析token字符串并获取
app.get('/api/getinfo', (req, res) => {
console.log(req.user)
res.send({
status: 200,
msg: '获取用户信息成功',
data: req.user
})
})
// 捕获token验证错误中间件
app.use((err, req, res, next) => {
if (err.name === 'UnauthorizedError') {
return res.send({
status: 401,
msg: '无效的token'
})
}
res.send({
status:500,
msg:'未知的错误'
})
})
app.listen(80, () => {
console.log('http://127.0.0.1')
})