目录
服务端生成token 和 解密认证 token (Node.js)
token 的使用过程
- 客户端使用用户名跟密码请求登录
- 服务端收到请求,去验证用户名与密码
- 验证成功后,服务端会签发一个 Token,再把这个 Token 发送给客户端
- 客户端收到 Token 以后可以把它存储起来,比如放在 Cookie 里或者 Local Storage 里
- 客户端每次向服务端请求资源的时候需要带着服务端签发的 Token
- 服务端收到请求,然后去验证客户端请求里面带着的 Token,如果验证成功,就向客户端返回请求的数据
- APP登录的时候发送加密的用户名和密码到服务器,服务器验证用户名和密码,如果成功,以某种方式比如随机生成32位的字符串作为token,存储到服务器中,并返回token到APP,以后APP请求时
- 凡是需要验证的地方都要带上该token,然后服务器端验证token,成功返回所需要的结果,失败返回错误信息,让他重新登录。其中服务器上token设置一个有效期,每次APP请求的时候都验证token和有效期。
服务端生成token 和 解密认证 token (Node.js)
需要下载的模块:
npm i jsonwebtoken basic-auth -S
jsonwebtoken : 用于生成 token
basic-auth : 用于解密 token
代码已模块化封装
token 加密模块
const jwt = require('jsonwebtoken')
//设置过期时间
let security = {
secretKey: 'asdjkl', //随便打,参与加密的字符
expiresIn: 60 * 60 * 24 * 3 //三天过期时间
}
// token 加密生成 uid:使用时间戳保证每次生成的token都不一样, scop:参与加密的数字
function genToken(uid, scope = 2) {
//获取 加密字符
const secretKey = security.secretKey
//获取 过期时间
const expiresIn = security.expiresIn
//进行加密,
const token = jwt.sign({
uid,
scope
}, secretKey, {
expiresIn
})
return token
}
//导出
module.exports = genToken
token 解密认证模块
const basicAuth = require('basic-auth')
const Err = require('../config/err')
const security = require('./tokentime')
const jwt = require('jsonwebtoken')
//主要作用,解密 token 获取 uid
class Auth {
constructor() {}
//取值函数 set 存值函数
get m() {
//返回一个中间件
return (req, res, next) => {
//token 一般都放到 请求头中
// console.log(req.headers.authorization)
//把 req 传进去,并获取 token
let token = basicAuth(req)
// console.log('token' + token);
//如果没有 token 那就没有访问权限
if (!token || !token.name) {
res.status(401).send(
new Err({
code: 401,
msg: '没有权限访问'
})
)
}
try {
//传 token.name 和 参与加密的值 进行解密
//返回`{ uid: '1636378082142', scope: 2, iat: 1636386518, exp: 1636645718 }`
var authcode = jwt.verify(token.name, security.secretKey)
} catch (err) {
//jwt 提供的'TokenExpireError'错误对象,表示token 已过期
if (err.name == 'TokenExpireError') {
res.status(401).send(
new Err({
code: 401,
msg: '账号过期,请登录'
})
)
}
res.status(401).send(
new Err({
code: 401,
msg: '没有权限访问'
})
)
}
//req是一个实例,往它的构造函数的原型中添加一个 auth 值,
//这样 所有的 req 都有 auth 了
req.__proto__.auth = {
uid: authcode.uid
}
// console.log(req.auth); //{ uid: '1636378082142' }
//如果有 throw 触发,就不会触发 next 了
//执行下一个中间件
next()
}
}
}
module.exports = {
Auth
}
调用认证模块 (每个接口都要加上 auth 认证哦)
//引入认证 中间件
var {
Auth
} = require('../token/auth')
var dishes_manage = require('../controller/dishes-info/dishes-manage')
//添加菜品接口
router.post('/addcategory', new Auth().m, dishes_manage.addcategory)
如果登录验证通过,就要响应 token 调用token加密模块
//登录接口
const login = async (req, res, next) => {
let { account, password } = req.body
//检测校验
new RegCheck(next, account, password).start()
try {
let sql = `select * from business_acc where account='${account}' and password='${password}'`
let result = await dbconfig.sySqlConnect(sql)
if (result.length) {
let uid = result[0].uid
//token加密
let toKen = genToken(uid)
new Result(res, "登陆成功", 200, {
toKen,
}).answer()
} else {
new Result(res, "账号或密码错误", 202).answer()
}
} catch (err) {
console.log(err)
new Result(res, "登录失败,服务器发生错误", 500).answer()
}
}
//Result 模块
/*
class Result {
constructor(res, msg = 'SUCCESS', code = 200, data = null, extra = null) {
this.res = res,
this.msg = msg,
this.code = code,
this.data = data,
this.extra = extra
}
answer() {
//设置响应信息
this.res.send({
msg: this.msg,
code: this.code,
data: this.data,
extra: this.extra
})
}
}
module.exports = Result
*/
客户端(Vue)
用户账号密码后端验证通过后,会响应 token,此时接收,并保存到 localStorage 中
localStorage.setItem("token", res.data.data.toKen)
然后就是使用 axios 的请求拦截,将 token 加到 请求头中
// http request 拦截器:是在ajax请求发出之前的操作
instance.interceptors.request.use(
config => {
let token = localStorage.getItem("token")
if (token) { // 判断是否存在token,如果存在的话,则每个http header都加上token
config.headers.Authorization = baseFun();
}
return config;
},
err => {
return Promise.reject(err);
});