乐趣区

jwt登陆校验携带token

jwt 登陆注册

jwt 概念

token 是不需要存储在数据库的, 只需要后台生成密钥,当客户端发送过来请求时那么就把 token 塞在请求体或者头中,客户端接收到 token 时那么就存储在 localStorage 或者 cookie 中,注意这里不能把敏感信息进行 token 存储,要不然会被获取到(比如 cookie 中或者请求体中)并且进行反向解密从而暴露敏感信息,比如密码;
token 中包含三块都是以

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9// 头信息这个是固定写死的 {'type': 'JWT','alg': 'HS256'}
.
> eyJ1c2VyIjoid2FuZyIsImVudmlyb25tZW50Ijoid2ViIiwiZXhwaXJlcyI6MTUzNTUyMDk1MTcxOX0// 载体 就是比如客户端发过来的 username
.
> 4rmP6UeeJ3mQbHfplruH15PvuUxPzFTxAfVnPgA7sgo// 密钥
根据将头和载体进行转换 base64 编码,然后在将头和载体根据 sha256 算法加密生成密钥(也就是第三步)这样就组成了一个 token,将这种思路换成代码就会实现 jwt-smilp 包中的 encode, 那么 decode 就是获取到进行反向解码 
jwt-smilp 中的 encode 和 decode
{username:username}// 载体 载体中还可以设置时间以及其他
 jwt.encode({username:username},sercet)//sercet 自己定义的密钥
 jwt.encode(token,sercet)// 进行解密 
登陆注册全过程

进入登陆页, 输入账号和密码点击登陆请求接口,后台会在数据库中寻找对应的账号密码 如果存在那么后台会生成一个 token 并且塞在请求头(或者响应体中), 给前端之后,前端获取返回值 并且存放在 cookie 中或者请求头中,前端通过 axios 中的请求拦截给请求头中塞进密钥,这样每次发送请求就会携带 token,后台接收到 token 之后会进行解码校验是否是正确的 token,如果是的话就进行下一步操作,如果不是的话就给前端提示

node 后台代码的实现

将 node 框架搭好之后新建一个 src 的文件下新建一个 app.js 的文件代码如下

let express = require('express')
let app = express()
// 获取 req 的 body
let bodyParser = require('body-parser');

// 引入自己写的登陆校验是否合规文件
let retoken = require('./retoken/retoken.js')

//bodyParser 对应的以下两个也是解析 post 中的 json 数据
app.use(express.json())

//urlencoded 解析 x -ww-form-urlencoded 请求体
app.use(express.urlencoded())

// 返回的对象是一个键值对,当 extended 为 false 的时候,键值对中的值就为 'String' 或 'Array' 形式,为 true 的时候,则可为任何数据类型
app.use(bodyParser.urlencoded({ extended: true}))

// 使用上面自己的写的中间件
app.use(retoken)

// 登陆接口文件
app.use('/login', require('./login/index.js'));


// 统一处理错误信息
app.use((err, req, res, next) => {if (err) {res.status(500).json({message: err.message})
    }
})

// 默认监听 3000 端口
app.listen(3000, () => {console.log('服务启用成功');
})
retoken.js
// 使用第三方插件
let jwt = require('jwt-simple');
// 定义加密和解密的密钥(随便写)const jstSecret = 'mengyuhang'

 function checkToken(req,res,next){
 // 判断如果是登陆接口或者注册接口那么就不需要校验 token
 if(req.url!='/login/login'&&req.url!='/login/create'){
 // 这里前端是直接将 token 塞到了 cookie 中所以我直接在 cookie 中获取
        let tokenClone = req.headers.cookie;
//token 传递过来的为这种形式:token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6Im15aDEyMyIsImV4cGlyZXMiOjE1OTQwNDU4NDc1NzN9.PwIAp3nXIscIvgXykjQumO6CbIFceHpGz6-2PUHgQU4

// 截取等号后面的
        let token = tokenClone.split('=')[1]
        if(token){// 如果存在那么解码,我这里加密的用户名和校验时间是否过期 { username: 'myh123', expires: 1594045847573}
            var decoded = jwt.decode(token, jstSecret)
            // 如果现在的时间超过了我设置的登陆时间那么就返回登陆过期
            if(Date.now()>decoded.expires){
                res.json({
                    code:'-2',
                    message: '登陆过期'
                })
            }else{
            // 否则向下执行
              next()}
        }else{
        // 如果没有 token 那么返回提示
            res.status(401).json({
                code:"-1",
                message: 'you need login:there is no token'
            })
        }
    }else{
    // 如果为登陆或者注册接口直接向下进行
        next()}
    
}
module.exports=checkToken
login.js 中的接口书写
const express = require('express');
let router = express.Router();
// 我这里使用 sequelize 操作数据库
let sequelize = require('sequelize')
let models = require('../../db/models')

let jwt = require('jwt-simple');
// 设置 token 的过期时间
const tokenExpiresTime = 1000 * 60 * 60 * 24 * 7
// 密钥
const jstSecret = 'mengyuhang'

router.post('/login', async (req, res, next) => {let { username, password} = req.body;
    try {
    // 在数据库中的 user 表中寻找对应的账号密码
        let personalInformation = await models.User.findOne({
            where: {
                username,
                password
            }
        })
        // 如果账号存在
        if (personalInformation) {
            // 生成 token
            // 需要加密的对象
            let payload = {
                username: personalInformation.username,
                expires: Date.now() + tokenExpiresTime}
            //jwt-simple 包提供的加密方法,jstSecret 自己定义的密钥
            let token = jwt.encode(payload, jstSecret)
            res.json({
                message: '登陆成功',
                token
            })
        } else {
        // 如果账号不存在
            res.json({
                code: '-1',
                message: '用户不存在,请校验信息是否正确'
            })
        }
    } catch (e) {
        res.json({message: '错误'})
    }


})
// 注册接口
router.post('/create', async (req, res, next) => {let { username, password} = req.body;
    try{
    // 在数据库中寻找用户名
        let user = await models.User.findOne({
            where: {username}
        })
        // 如果用户名存在
        if (user) {
            res.json({
                code: '-1',
                message: '用户名已存在'
            })
        } else {
        // 如果用户名不存在就可以注册成功啦
            await models.User.create({
                username,
                password
            })
            res.json({
                code: '0',
                message: '注册成功'
            })
        }
    }catch(e){next()
    }
    
})


module.exports = router

前端登陆

点击登陆时获取到后台返回的 token 之后直接塞在 document.cookie 中即可

退出移动版