node实战——后端koa结合jwt连接mysql实现权限登录(node后端就业储备知识)

文章目录

    • ⭐前言
    • ⭐ 环境准备
    • ⭐ 实现过程
      • ⭐ mysql 配置
      • ⭐路由前的准备
      • ⭐账号注册生成token
      • ⭐账号登录生成token
      • ⭐token登录
    • ⭐ 自测过程截图
    • ⭐总结
    • ⭐结束

yma16-logo

⭐前言

大家好,我是yma16,本文分享关于node实战——后端koa项目配置jwt实现登录注册(node后端就业储备知识)。
本文适用对象:前端初学者转node方向,在线大学生,应届毕业生,计算机爱好者。
node系列往期文章
node_windows环境变量配置
node_npm发布包
linux_配置node
node_nvm安装配置
node笔记_http服务搭建(渲染html、json)
node笔记_读文件
node笔记_写文件
node笔记_连接mysql实现crud
node笔记_formidable实现前后端联调的文件上传
node笔记_koa框架介绍
node_koa路由
node_生成目录
node_读写excel
node笔记_读取目录的文件
node笔记——调用免费qq的smtp发送html格式邮箱
node实战——搭建带swagger接口文档的后端koa项目(node后端就业储备知识)
jwt的发展

JWT(JSON Web Token)是一种开放标准(RFC 7519),用于在不同应用程序或服务之间安全地传输信息和声明。它最初由JWT工作组在2015年发布,现在已成为Web应用程序和API的常见身份验证和授权方案之一。JWT标准建立在JSON数据格式上,由三个部分组成:头部 header、载荷 payload、签名 Authorization。它们共同构成了一个包含声明信息的安全令牌。
JWT的发展可以追溯到OAuth 2.0协议,它是OAuth 2.0协议的一种扩展。JWT的目的是为了解决OAuth 2.0协议中的一些缺点,例如在使用OAuth 2.0协议时,每次请求都需要向OAuth服务器进行验证。使用JWT可以避免这种验证,因为JWT包含了所有必要的信息,服务器可以直接验证JWT的签名以确认用户的身份。
随着云计算和移动设备应用的普及,JWT已经成为了Web应用程序和API的一种标准身份验证和授权方案。同时,围绕JWT的生态系统也在不断壮大。例如,OAuth 2.0协议和OpenID Connect协议都已经支持JWT作为身份验证和令牌颁发方案。
总之,JWT是一种开放的、安全的、跨平台的身份验证和授权方案,它为不同应用程序和服务之间的安全通信提供了便利。随着时间的推移,JWT的发展已经越来越成熟,它将继续在Web应用程序和API的身份验证和授权领域发挥重要作用。

注册
register

登录
login

⭐ 环境准备

安装koa 需要的依赖

$ npm install koa koa-jwt koa-bodyparser koa2-cors koa-router koa2-swagger-ui mysql

官方文档用法

var Koa = require('koa');
var jwt = require('koa-jwt');

var app = new Koa();

// Custom 401 handling if you don't want to expose koa-jwt errors to users
app.use(function(ctx, next){
  return next().catch((err) => {
    if (401 == err.status) {
      ctx.status = 401;
      ctx.body = 'Protected resource, use Authorization header to get access\n';
    } else {
      throw err;
    }
  });
});

// Unprotected middleware
app.use(function(ctx, next){
  if (ctx.url.match(/^\/public/)) {
    ctx.body = 'unprotected\n';
  } else {
    return next();
  }
});

// Middleware below this line is only reached if JWT token is valid
app.use(jwt({ secret: 'shared-secret' }));

// Protected middleware
app.use(function(ctx){
  if (ctx.url.match(/^\/api/)) {
    ctx.body = 'protected\n';
  }
});

app.listen(3000);

初始化项目搭建请查看我写的这篇博客:node实战——搭建带swagger接口文档的后端koa项目(node后端就业储备知识)

⭐ 实现过程

注册过程分解:

  1. 查询用户名是否在user表存在
  2. 注册用户名已存在则登录
  3. 注册用户名不存在则插入用户数据

登录过程分解:

  1. 查询用户密码是否对应user表的数据
  2. 存在则根据用户名密码生成token
  3. 不存在抛出错误

token登录过程分解:

  1. 解析web端传递的token
  2. 拿出其中的用户名密码在数据库查询存在则登录成功

⭐ mysql 配置

封装mysql连接传递一个sql语句来运行即可

const mysql = require('mysql');

const config ={
    host     : 'ip',
    user     : '账号',
    password : '密码',
    database : '数据库模式'
}
// 把这个方法抛出去
const execMysql=(sql)=>{
    return new Promise((resolve,reject)=>{
        // 连接mysql
        const connection = mysql.createConnection(config);
        try{
            connection.query(sql, function (error, results) {
                if (error){
                    reject(error)
                };
                resolve(results)
            });


        }
        catch (e) {
            reject(e)
        }
        finally {
            connection.end()
        }
    })
};

module.exports={
    execMysql
}

⭐路由前的准备

初始化router

const Router = require('koa-router');
const router = new Router();
const {execMysql}=require('../../utils/mysql/index')
const jwtToken = require("jsonwebtoken");

// 唯一字符串
function uuid() {
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
        var r = Math.random() * 16 | 0,
            v = c == 'x' ? r : (r & 0x3 | 0x8);
        return v.toString(16);
    });
}

// 当前时间
const  getCurrentTime=() =>{
    const now = new Date()
    const year = now.getFullYear()
    const month = now.getMonth()
    const date = now.getDate()
    const hour = now.getHours()
    const minutes = now.getMinutes()
    const second = now.getSeconds()
    const formatNum = (n) => {
        return n > 9 ? n.toString() : '0' + n
    }
    return `${year}-${formatNum(month + 1)}-${formatNum(date)} ${formatNum(hour)}:${formatNum(minutes)}:${formatNum(second)}`
}

⭐账号注册生成token

封装注册写入sql 生成token

// 注册
router.post('/register', async (ctx) => {
   try{
       // 解析参数
       const bodyParams =  ctx.request.body
       const {username,password} = bodyParams;
       if(!username||!password){
           return ctx.body = {
               code: 0 ,
               msg:'username or password is null'
           };
       }
       // 查询重复
       const search=await execMysql(`select count(1) as total from user where username='${username}';`)
       console.log('search',search)
       if(search[0].total>0){
           return ctx.body = {
               code: 0 ,
               msg:'user is exist'
           };
       }
       // id 唯一字符
       const id= uuid()
       const create_time=getCurrentTime()
       // 插入 数据
       const createRes=await execMysql(`INSERT INTO user (id,username,password,create_time) VALUES ('${id}', '${username}','${password}','${create_time}');`)

       // 更新token update_time
       const token=jwtToken.sign(
           {
               username,
               password
           },
           "yma16-app", // secret
           { expiresIn: 24 * 60 * 60 } // 60 * 60 s
       )
       const update_time=getCurrentTime()
       const tokenRes=await execMysql(`update user set token='${token}', update_time='${update_time}' where username='${username}';`)
       ctx.body = {
           code:200,
           data:{
               createSqlData:createRes,
               tokenSqlData:tokenRes
           },
           msg:' insert success',
           token:token
       };
   }
   catch (e) {
       ctx.body = {
           code:0,
           msg:e
       };
   }
});

⭐账号登录生成token

账号密码生成token

// 获取token
router.post('/token/gen', async (ctx) => {
    try{
        // 解析参数
        const bodyParams =  ctx.request.body
        const {username,password} = bodyParams;
        // 查询 用户
        const search=await execMysql(`select count(1) as total from user where username='${username}' and password='${password}';`)
        if(search[0].total>0){
            // 更新token update_time
            const token=jwtToken.sign(
                {
                    username,
                    password
                },
                "yma16-app", // secret
                { expiresIn: 24 * 60 * 60 } // 60 * 60 s
            )
            const update_time=getCurrentTime()
            // 更新token
            const tokenRes=await execMysql(`update user set token='${token}', update_time='${update_time}' where username='${username}';`)
            // 配置token
            const AUTHORIZATION='Authorization'
            ctx.set(AUTHORIZATION,token)
            return ctx.body = {
                code:200,
                msg:'login success',
                token:token
            };
        }

        ctx.body = {
            code:0,
            msg:' login fail',
        };
    }
    catch (e) {
        ctx.body = {
            code:0,
            msg:e
        };
    }
});

⭐token登录

用户使用token登录

// token 登录
router.post('/token/login',async (ctx) => {
    try{
        // 解析参数
        const bodyParams =  ctx.request.body
        const {token} = bodyParams;
        const payload = jwtToken.verify(token, 'yma16-app');
        console.log('token',token)
        const {username,password} =payload
        // 查询重复
        // 查询 用户
        const search=await execMysql(`select count(1) as total from user where username='${username}' and password='${password}';`)
        if(search[0].total>0){
            const last_login_time=getCurrentTime()
            // last_login_time  登录时间
            const tokenRes=await execMysql(`update user set last_login_time='${last_login_time}' where username='${username}' and password='${password}';`)
            return ctx.body = {
                code:200,
                msg:'login success',
                data:{
                    username
                }
            };
        }

        ctx.body = {
            code:0,
            msg:' login fail',
        };
    }
    catch (e) {
        console.log('e',e)
        ctx.body = {
            code:0,
            msg:JSON.stringify(e)
        };
    }
})

⭐ 自测过程截图

生成token
gentoken
选择 authoration 为 beare token传递token 在 body的传递自定义token请求登录成功
token login success
数据库表写入 用户名、密码、token、创建时间、更新时间、最近登录时间 成功!
create sql data

⭐总结

注意事项:

  1. jwt 前后的 Authorization 保持一致
  2. 给注册页面开启白名单,不需要jwt校验
  3. 注意过去的expire时间,调试的时候调大一点

前后端加上aes加密更安全
后端node配置

const aesCrypto = require('crypto-js/aes');
const utf8Encode = require("crypto-js/enc-utf8")

const secretKey = "yma16-app"

// 加密
const encrypt = text => {
    let encryptedText = aesCrypto.encrypt(utf8Encode.parse(text), secretKey).toString();

    return encryptedText
}

// 解密
const decrypt = text => {
    let decryptText = aesCrypto.decrypt(text, secretKey).toString(utf8Encode)

    console.log(decryptText)

    return decryptText.toString(utf8Encode);
}

exports.aes = { encrypt, decrypt }

前端vue3配置
安装 crypto-js
定义加密解密方法

// @ts-ignore
import CryptoJS from 'crypto-js';

export const globalEnv=()=>{
    return import.meta.env
};

const key='yma16-app'
export const aes:any={
    //加密
    encrypt(word:string, keyStr?:any) {
        keyStr = keyStr ? key : 'yma16-app';
        var key = CryptoJS.enc.Utf8.parse(keyStr);
        var srcs = CryptoJS.enc.Utf8.parse(word);
        var encrypted = CryptoJS.AES.encrypt(srcs, key, { mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.Pkcs7 });
        return encrypted.toString();
    },
    //解密
    decrypt(word:string, keyStr?:any) {
        keyStr = keyStr ? key : 'abcdsxyzhkj12345';
        var key = CryptoJS.enc.Utf8.parse(keyStr);
        var decrypt = CryptoJS.AES.decrypt(word, key, {mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.Pkcs7});
        return CryptoJS.enc.Utf8.stringify(decrypt).toString();
    }
};

⭐结束

本文分享到这结束,如有错误或者不足之处欢迎指出!
gaoda-img

👍 点赞,是我创作的动力!
⭐️ 收藏,是我努力的方向!
✏️ 评论,是我进步的财富!
💖 最后,感谢你的阅读!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/109716.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

博客模板博客模板

xservices-bpm-6.2.1.1.jar 本人详解 作者:王文峰,参加过 CSDN 2020年度博客之星,《Java王大师王天师》作者 公众号:山峯草堂,非技术多篇文章,专注于天道酬勤的 Java 开发问题、中国国学、传统文化和代码爱…

智慧矿山AI算法助力护帮板支护监测,提升安全与效率

在智慧矿山AI算法系列中,护帮板支护监测是保障矿山安全和提高生产效率的重要环节。护帮板作为矿山支护体系中的重要组成部分,在矿山生产中起到了关键的作用。那么,护帮板在哪种状态下是正常打开的呢?本文将对此进行介绍。 护帮板的…

LeetCode热题100 240.搜索二维矩阵||

题目描述: 编写一个高效的算法来搜索 m*n 矩阵 matrix 中的一个目标值 target 。该矩阵具有以下特性: 每行的元素从左到右升序排列。每列的元素从上到下升序排列。 示例1: 输入:matrix [[1,4,7,11,15],[2,5,8,12,19],[3,6,9,16,2…

「实验记录」CS144 Lab0 networking warmup

文章目录 一、Motivation二、SolutionsS1 - Writing webgetS2 - An in-memory reliable byte stream 三、Results四、Source 一、Motivation 第一个小测试 webget 是想让我们体验并模拟一下在浏览器中键入 URL 后获得远程服务器传来的内容,这并没有太大的难度&…

【IDEA】设置sql提示

第一步:注入SQL语言 1.首先选择任意一条sql语句,右击,选择 ‘显示上下文操作’ 2.选择 ‘注入语言或引用’ 3. 往下翻,找到MySQL 第二步:配置MySQL数据库连接 1.首先点击侧边的数据库,再点击上面的加号 2…

OpenCV官方教程中文版 —— Hough 圆环变换

OpenCV官方教程中文版 —— Hough 圆环变换 前言Hough 圆环变换 前言 目标 • 学习使用霍夫变换在图像中找圆形(环) • 学习函数:cv2.HoughCircles() Hough 圆环变换 opencv_logo.png: # -*- coding: utf-8 -*- import cv2 …

基于STC12C5A60S2系列1T 8051单片机可编程计数阵列CCP/PCA/PWM模块的PWM(脉冲宽度调制)应用

基于STC12C5A60S2系列1T 8051单片机可编程计数阵列CCP/PCA/PWM模块的PWM(脉冲宽度调制)应用 STC12C5A60S2系列1T 8051单片机管脚图STC12C5A60S2系列1T 8051单片机I/O口各种不同工作模式及配置STC12C5A60S2系列1T 8051单片机I/O口各种不同工作模式介绍STC…

设备完全有效生产率TEEP对生产制造企业有什么作用?

设备完全有效生产率(Total Effective Efficiency of Production,简称TEEP)是反映企业设备效率的一项重要指标,用于评估生产制造企业的设备利用率和生产效率。本文将从三个方面探讨TEEP的含义、计算方法以及对生产制造企业的作用。…

回收废品抢派单小程序开源版开发

回收废品派单抢派单小程序开源版开发 在这个废品回收抢单派单小程序开源版开发中,我们将构建一个专业且富有趣味性的平台,以深度的模式来重塑废品回收体验。 我们将提供一个会员注册功能,用户可以通过小程序授权注册和手机号注册两种方式快…

Leetcode—2558.从数量最多的堆取走礼物【简单】

2023每日刷题&#xff08;十二&#xff09; Leetcode—2558.从数量最多的堆取走礼物 大顶堆实现代码 void swap(int *a, int *b) {int tmp *a;*a *b;*b tmp; }void downAdjustHeap(int *heap, int low, int high) {int i low;int j 2 * i 1;while(j < high) {if(j …

气膜场馆里面噪声很大怎么解决?

随着气膜结构在各个领域的广泛应用&#xff0c;人们开始意识到在这些场馆内部&#xff0c;特别是在大型活动和展览中&#xff0c;噪声问题可能会变得相当严重。传统的气膜结构通常难以提供良好的声学环境&#xff0c;这对于参与者的舒适度和活动的质量构成了挑战。为了解决气膜…

国外怎么传大文件到国内,这款传输软件跨国企业必备

从国外传输文件到国内&#xff0c;这项任务常常充满了挑战。国际之间的距离、网络延迟、数据安全和文件大小限制等问题使得这个过程异常复杂。本文将深入剖析这些挑战&#xff0c;并说明一款优秀的跨国传输软件&#xff0c;如何能够成为解决这些问题的强有力工具。 国外传输文件…

ice和Dtls 传输的创建及1个简单的SFU转发实例

ice和Dtls 传输的创建及1个简单的SFU转发实例 licode中,webrtcconn基于dtlstransport 收发,而dtlstransport通过libnice作为底层。dtlstransport 使用了srtp加解密。文末给出一个简化的sfu实例的实现。对应的,看下M98的代码,更能理解为啥这么做: IceTransportInternal 与D…

一天收入500元的货拉拉运费差项目靠谱吗?

最近的货拉拉运费差项目有点火呀&#xff01;收费也不低&#xff0c;1680-16980的比比皆是。 这个项目去年我就在某些平台看到过&#xff0c;今天就跟大家详细聊聊这个项目&#xff0c;想入坑的不妨先看看这篇文章。 一&#xff1a;项目原理 有人叫它货拉拉搬砖项目&#xf…

檢測項目簡體字

某些項目可能要求代碼中不允許使用簡體字 安裝stcheck檢查 yarn add stcheck --dev在項目根目錄創建 st.config.json 文件 {"patterns": ["./**/*.(ts|js|tsx|jsx|vue|html)","!**/node_modules/**","!.git/**"],"gitignore&q…

RabbitMQ学习05

文章目录 交换机1.Exchanges1.1 概念1.2 类型1.3 无名exchange 2. 临时队列3. 绑定&#xff08;bings&#xff09;4. Fanout4.1 介绍 5.Direct exchange5.1 介绍5.2 多重绑定5.3 实战: 6. Topics6.1 规则6.2 实战 交换机 1.Exchanges 1.1 概念 RabbitMQ 消息传递模型的核心思…

真实感渲染的非正式调研与近期热门研究分享

真实感渲染的非正式调研与近期热门研究分享 1 期刊1 Top2 Venues 2 Rendering Reserach1 Material2 BRDF3 Appearance Modeling4 Capture5 Light Transport光线传播6 Differetiable Rendring-可微渲染7 Ray Tracing8 Denoising降噪9 NeRF 3 VR/AR4 Non-Photorealistic Renderin…

[GKCTF 2021]easycms 禅知cms

一道类似于渗透的题目 记录一下 首先扫描获取 登入界面 admin/12345登入 来到了后台 然后我们开始测试有无漏洞点 1.文件下载 设计 自定义 导出 然后进行抓包 解密后面的内容 发现是绝对路径了 所以这里我们要获取 flag 就/flag即可 L2ZsYWc /admin.php?mui&fdownlo…

从历史的探索到RFID固定资产管理的未来

在人类历史上&#xff0c;技术的进步一直是推动社会和工业发展的关键因素。其中&#xff0c;RFID技术的出现是一个重要的里程碑。让我们回顾一下RFID技术的历史&#xff0c;并探讨如何将其应用于固定资产管理&#xff0c;为企业提供更高效、智能的解决方案。 RFID&#xff08;R…

企业文件防泄密方法

企业文件防泄密方法 安企神数据防泄密系统下载使用 企业文件是企业的核心资产&#xff0c;其中可能包含大量的敏感信息&#xff0c;如客户资料、产品配方、财务数据等。一旦这些文件泄露&#xff0c;可能会给企业带来不可估量的损失。 然而&#xff0c;企业文件防泄密是确保…