首先将用户信息传递通过浏览器传递给服务器,服务器进行验证,服务器验证之后加密生成token字符串,直接将token字符串响应给浏览器。浏览器中将token字符串存储到localstorag或sessionstorage中,客户端需要再次发起请求的时候,通过请求头的Authorization字段,将Token发给服务器,服务器将token字符串解析,服务器身份认证成功 响应成功
安装生成token和压缩token的包:jsonwebtoken \ express-jwt

//ES6的语法——需要覆盖字符串的内容——token的安全性:在token加密中不推荐保存密码等指之类的敏感信息
const user={...results[0],password:'',user_pic:''}//ES6的语法——需要覆盖字符串的内容
首先导入包:
- //导入生成token的包
- const jwt=require('jsonwebtoken')
-
- //导入全局的配置文件——里面有加密解析token的密钥
- const config=require('../config')
token实现需要密钥:——使用中间件
- //全局的配置中间件
-
- //我们需要专门定义一个用于加密和解密的secret密钥——中间件
- module.exports = {
- jwtSecretKey: 'abdbdodjod-^-^-',
- //有效期
- expiresIn:'10h',
- }
实现token生成//调用jsonwebtoken包中的sign()方法,将用户的信息加密生成JWT字符串,响应给客户端
- //调用jsonwebtoken包中的sign()方法,将用户的信息加密生成JWT字符串,响应给客户端
- const tokenStr=jwt.sign(user,config.jwtSecretKey,{expiresIn:config.expiresIn})
调用res.send()将token响应给客户端
- console.log(tokenStr)//测试
- res.send(
- {
- status:0,
- message:'登录成功',
- token:'Bearer '+tokenStr,//字符串的拼接方便将token直接夹存在浏览器中之后发起请求头
- }
- )//响应给客户端的话

解析token)——在路由之前
- //导入解析jwt的包
- var { expressjwt: expressJWT } =require('express-jwt')
- //导入全局的配置文件——里面有加密解析token的密钥
- const config=require('./config')
- //之后需要将客户端中的token,还原成字符串全局生效的中间件
- app.use(expressJWT({secret:config.jwtSecretKey,algorithms: ["HS256"]}).unless({path:[/^\/api/]}))//除去/api开头的不需要转义
还有一个toke出错需要捕获:放在最后
-
- //定义错误级别中间件
- app.use(function(err, req, res, next) {
- //验证失败导致的错误
- if (err instanceof joi.ValidationError) {//验证的方式
- return res.cc(err.message)
- }
- //身份认证失败后的错误
- if(err.name === "UnauthorizedError"){
- return res.cc('身份认证失败')
- }
- return res.cc('未知的错误')
- })
测试:
/c开头的认证失败,需要身份认证——需要进行expressJWT,token判断请求头中是否含有请v求头 Authorization : Bearer空格

发送了请求头,token成功了,但是由于服务器没有这个给接口,所以也是失败的

全部函数:路由处理函数模块:
![]()
- //对应的路由处理函数
-
- //导入数据库操作模块
- const db=require('../db/index')
- //检测数据库是否导入成功
- // db.query('select 1',(err,results)=>{
-
- // if(err) return console.log(err.message)
-
- // console.log(results)//此结果可以正常打印输出就表示数据库连接正常
-
- // })
- //导入bcryptjs包对明文密码进行加密
- const bcrypt=require('bcryptjs')
- //导入生成token的包
- const jwt=require('jsonwebtoken')
- //导入全局的配置文件——里面有加密解析token的密钥
- const config=require('../config')
-
- //这是注册新用户的处理函数
- const regUser=function(req,res){//postreq.body
- //获取客户端提交给服务器的用户信息
- const userInfo=req.body
- //console.log(userInfo)——测试是否接收到表单数据
- //*********对表单中的数据进行合法性的校验_____放到了表单数据传入的部分
-
- //定义SQL语句,查询用户名是否被占用
- const sqlStr='select * from ev_users where username=?'//sql语句
- db.query(sqlStr,[userInfo.username],(err,results)=>{
- //执行SQL语句失败_
- if(err) return res.cc(err)
- //select查询的结果是数组,用户名被占用——查询不会影响行数
- if(results.length>0) return res.cc('用户名被占用,请更换用户名')
- //用户名可用使用
- //调用bcrypt.hashSync进行加密--归还给userInfo
- userInfo.password=bcrypt.hashSync(userInfo.password,10)//加密的内容
- //console.log(userInfo)
-
- //定义插入新用户的SQL语句——插入的少使用表(字段)values(值) 插入多使用set
- const sqlStr1='insert into ev_users set ?'
- db.query(sqlStr1,{username:userInfo.username,password:userInfo.password},(err,results)=>{
- //执行SQL语句失败_
- if(err) return res.cc(err)
- //判断插入失败
- if(results.affectedRows!==1)return res.cc('注册用户失败,请稍后再试!')
- //c成功传参
- res.cc('注册用户成功!',0)
-
- })
-
- })
-
- }
- //这是登录的处理函数
- const login=function(req,res){//post
- userInfo=req.body//接收表单数据
- //定义查询用户的SQL语句
- const sqlStr='select * from ev_users where username= ?'
- db.query(sqlStr,userInfo.username,(err,results)=>{
- //执行SQL语句失败_
- if(err) return res.cc(err)
- //判断查询失败--result里面存的是数组
- if(results.length!==1) return res.cc('用户名不存在,请重新登录')
- //密码的验证——直接使用等号是不行的,
- //我们在用户注册的时候调用bcrypt.hashSync对密码进行加密————存储
- //results[0]查出来的第一项
- const compareResults= bcrypt.compareSync(userInfo.password, results[0].password)
- if(!compareResults) return res.cc('密码错误,请重新登录!')
-
- //用户密码用户名成功之后——token操作
- //在服务器端生成Token的字符串
- // console.log({...results[0]})//查询数据的数组内容
- const user={...results[0],password:'',user_pic:''}//ES6的语法——需要覆盖字符串的内容
- //console.log(user)//测试
- //调用jsonwebtoken包中的sign()方法,将用户的信息加密生成JWT字符串,响应给客户端
- const tokenStr=jwt.sign(user,config.jwtSecretKey,{expiresIn:config.expiresIn})
- //console.log(tokenStr)//测试
- res.send(
- {
- status:0,
- message:'登录成功',
- token:'Bearer '+tokenStr,//字符串的拼接方便将token直接夹存在浏览器中之后发起请求头
- }
- )//响应给客户端的话
-
-
- })
-
- }
- //向外暴露
- module.exports={
- regUser,
- login
- }
token密钥模块:

- //全局的配置中间件
-
- module.exports = {
- //
- //我们需要专门定义一个用于加密和解密的secret密钥——中间件
- jwtSecretKey: 'abdbdodjod-^-^-',
- //有效期
- expiresIn:'10h',
- }
服务器模块:
-
- //导入express模块
- const express=require('express')
- //创建web服务器
- const app=express()
-
- // 导入 cors 中间件——支持跨域访问
- const cors = require('cors')
- // 将 cors 注册为全局中间件
- app.use(cors())
-
- //配置解析application/x-www-form-urlencoded格式数据的内置中间件
- app.use(express.urlencoded({ extended: false }))//extended默认值
- //导入表单数据中间件
- const joi=require('joi')
- //在路由之前,封装函数
- // 响应数据的中间件
- app.use(function (req, res, next) {
- // status = 0 为成功; status = 1 为失败; 默认将 status 的值设置为 1,方便处理失败的情况
- res.cc = function (err, status = 1) {//status默认失败——传参
- res.send({
- // 状态
- status,
- // 状态描述,判断 err 是 错误对象 还是 描述错误字符串
- message: err instanceof Error ? err.message : err,//instanceof是否是Error实例
- })
- }
- next()//流转关系传下去
- })
- //导入解析jwt的包
- var { expressjwt: expressJWT } =require('express-jwt')
- //导入全局的配置文件——里面有加密解析token的密钥
- const config=require('./config')
- //之后需要将客户端中的token,还原成字符串全局生效的中间件
- app.use(expressJWT({secret:config.jwtSecretKey,algorithms: ["HS256"]}).unless({path:[/^\/api/]}))//除去/api开头的不需要转义
-
- //导入并使用用户的路由模块
- const userRouter=require('./router/user.js')
- app.use('/api',userRouter)//加上统一的前缀——将其注册成为全局可以用的路由模块
-
- //定义错误级别中间件
- app.use(function(err, req, res, next) {
- //验证失败导致的错误
- if (err instanceof joi.ValidationError) {//验证的方式
- return res.cc(err.message)
- }
- //身份认证失败后的错误
- if(err.name === "UnauthorizedError"){
- return res.cc('身份认证失败')
- }
- return res.cc('未知的错误')
- })
- //启动服务器、使用3007端口
- app.listen(3007,()=>{
- console.log('http://127.0.0.1:3007 服务器启动成功')
- })