nodejs ,koa-bodyparser,koa-router,koa-static, JWT 编写的一个可权限控制的后端(ES6 style)以及展示用户登录、注册的前端_koa权限管理-程序员宅基地

技术标签: Powered by 金山文档  Nodejs  javascript  

1、安装组件

npm install koa koa-bodyparser koa-router koa-static koa-views jsonwebtoken
  1. 项目结构

project/
├── public/
│   ├── index.html
│   └── dashboard.html
└── App.mjs

2、App.mjs

import Koa from 'koa';
import koaBody from 'koa-bodyparser';
import koaRouter from 'koa-router';
import koaStatic from 'koa-static';
import jwt from 'jsonwebtoken';
import fs from 'fs';
import path from 'path';

const app = new Koa();
const router = new koaRouter();

app.use(koaBody());
app.use(koaStatic('public'));
/*
  模拟用户密码数据库
*/
const users = [
  {
    email: '[email protected]',
    password: 'password1',
    role: 'user',
  },
  {
    email: '[email protected]',
    password: 'password2',
    role: 'user',
  },
  {
    email: '[email protected]',
    password: 'adminpassword',
    role: 'admin',
  },
];

function generateToken(user) {
  const token = jwt.sign({ email: user.email, role: user.role }, 'secret_key', {
    expiresIn: '1h',
  });
  return token;
}

function authenticate(email, password) {
  const user = users.find((user) => user.email === email && user.password === password);
  return user;
}

router.post('/api/login', async (ctx) => {
  const { email, password } = ctx.request.body;
  const user = authenticate(email, password);
  if (!user) {
    ctx.status = 401;
    ctx.body = { message: 'Invalid login credentials' };
    return;
  }
  const token = generateToken(user);
  ctx.body = { token };
});

router.post('/api/register', async (ctx) => {
  const { email, password } = ctx.request.body;
  const user = { email, password, role: 'user' };
  users.push(user);
  const token = generateToken(user);
  ctx.body = { token };
});

function authMiddleware() {
  return async (ctx, next) => {
    const authHeader = ctx.request.headers.authorization;
    if (!authHeader) {
      ctx.status = 401;
      ctx.body = { message: 'Authorization header missing' };
      return;
    }
    const [bearer, token] = authHeader.split(' ');
    if (bearer !== 'Bearer' || !token) {
      ctx.status = 401;
      ctx.body = { message: 'Invalid Authorization header' };
      return;
    }
    try {
      const decoded = jwt.verify(token, 'secret_key');
      ctx.state.user = decoded;
      await next();
    } catch (err) {
      ctx.status = 401;
      ctx.body = { message: 'Invalid or expired token' };
    }
  };
}

router.get('/api/user', authMiddleware(), async (ctx) => {
  ctx.body = ctx.state.user;
});

router.get('/', async (ctx) => {
  ctx.redirect('/index.html');
});

app.use(router.routes());
app.use(router.allowedMethods());

const port = process.env.PORT || 3000;
app.listen(port, () => {
  console.log(`Server running on port ${port}`);
});
  1. index.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>Example App</title>
  </head>
  <body>
    <h1>Welcome to Example App</h1>
    <div>
      <h2>Login</h2>
      <form id="login-form">
        <div>
          <label for="email">Email:</label>
          <input type="email" name="email" id="email" />
        </div>
        <div>
          <label for="password">Password:</label>
          <input type="password" name="password" id="password" />
        </div>
        <div>
          <button type="submit">Login</button>
        </div>
      </form>
    </div>
    <div>
      <h2>Register</h2>
      <form id="register-form">
        <div>
          <label for="email">Email:</label>
          <input type="email" name="email" id="register-email" />
        </div>
        <div>
          <label for="password">Password:</label>
          <input type="password" name="password" id="register-password" />
        </div>
        <div>
          <button type="submit">Register</button>
        </div>
      </form>
    </div>

    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
    <script>
      $(document).ready(() => {
        $('#login-form').submit((event) => {
          event.preventDefault();
          const email = $('#email').val();
          const password = $('#password').val();
          $.post('/api/login', { email, password })
            .done((response) => {
              localStorage.setItem('token', response.token);
              window.location.href = '/dashboard.html';
            })
            .fail((xhr, status, error) => {
              alert(xhr.responseJSON.message);
            });
        });

        $('#register-form').submit((event) => {
          event.preventDefault();
          const email = $('#register-email').val();
          const password = $('#register-password').val();
          $.post('/api/register', { email, password })
            .done((response) => {
              localStorage.setItem('token', response.token);
              window.location.href = '/dashboard.html';
            })
            .fail((xhr, status, error) => {
              alert(xhr.responseJSON.message);
            });
        });
      });
    </script>
  </body>
</html>
  1. dashboard.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>Dashboard</title>
  </head>
  <body>
    <h1>Welcome to the Dashboard</h1>
    <p>You are logged in!</p>

    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
    <script>
      $(document).ready(() => {
        const token = localStorage.getItem('token');
        if (!token) {
          window.location.href = '/index.html';
        } else {
          $.ajax({
            url: '/api/user',
            method: 'GET',
            headers: { Authorization: `Bearer ${token}` },
          })
            .done((response) => {
              $('h1').append(`, ${response.email}!`);
            })
            .fail((xhr, status, error) => {
              alert(xhr.responseJSON.message);
              window.location.href = '/index.html';
            });
        }
      });
    </script>
  </body>
</html>

node.exe App.mjs 启动服务

在浏览器中访问 http://localhost:3000/ 查看应用程序。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/Sliphades/article/details/129180541

智能推荐

JFreeChart的使用_jfreechat使用-程序员宅基地

文章浏览阅读298次。前提:导入需要的2个jar文件,jcommon-版本号.jar,jfreechart-版本号.jar。可以去官网下载:http://sourceforge.net/projects/jfreechart/files/注意:下载的Jfreechart版本不要太高,新版本对中文的显示会出问题,我自己后来下的是1.0.10的版本。 实例一:比较简单的application版本的饼图 _jfreechat使用

「Python条件结构」显示学号及提示信息_从键盘上获取语文,数学,英语成绩并输出要求有良好的提示信息和良好的命名规范-程序员宅基地

文章浏览阅读1.3k次。编写一个控制台应用程序,从键盘中输入一个学生的学号,以及语文、数学、计算机的成就。a) 若是三门成绩之和>=280,显示学号及“是一个成绩优秀的学生!”;b) 若不满足该条件只要语文数学成绩均在95分以上,则显示学号及“语数成绩优秀!”;c) 以上条件都不满足,若计算机成绩是100分,则显示学号及“计算机成绩优秀!”;d) 所有条件都不满足,则显示学号及“仍需努力!”。..._从键盘上获取语文,数学,英语成绩并输出要求有良好的提示信息和良好的命名规范

SpringBoot+Mybatis-Plus整合Sharding-JDBC5.1.1实现分库分表_sharding jdbc 5.1.1 + mybatis plus 多数据源-程序员宅基地

文章浏览阅读1.1k次。SpringBoot+Mybatis-Plus整合Sharding-JDBC4.0.0实现单库分表 _sharding jdbc 5.1.1 + mybatis plus 多数据源

计算机联锁系统冗余试验,计算机联锁系统冗余技术及应用研究-程序员宅基地

文章浏览阅读593次。摘要:计算机联锁系统保持长期安全可靠运行对于铁路安全稳定运行至关重要,冗余技术是提高系统可靠性的主要手段,因此研究计算机联锁系统冗余技术具有重要意义.在主流冗余结构中,二乘二取二以其高可靠性和高安全性被广泛应用于国内外计算机联锁系统,但其核心技术被国外掌握,国内对基于该结构下的维护策略,冗余通信,联锁软件冗余等问题的研究仍显不足.为了获得更高的可靠性和安全性,本文针对二乘二取二计算机联锁系统展开研..._计算机联锁冗余方式哪个可靠性和安全性高

uc浏览器怎么开启电脑版,UC浏览器怎么开启无痕_uc浏览器 chrome csdn-程序员宅基地

文章浏览阅读188次。希腊文 Chromium 的本意是 "颜色"。1797年,法国化学家 L.N.Vauquelin 在西伯利亚红铅矿中发现一种新矿物,命名为 Chromium,中文的意思是铬,铬的化合物都有颜色Python解释器的安装步骤。铬是一种质地极其坚硬的银白色金属。2006年,谷歌把一款全新的浏览器命名为 Chromium ,并向全世界开放了源代码。现在 Chromium 成为世界上许多浏览器的坚强核心,占据了70%以上的电脑屏幕。浏览器 调试 JS。_uc浏览器 chrome csdn

oracle常用的经典sql查询_用oracle sql语句 查询 热门t-程序员宅基地

文章浏览阅读670次。oracle常用经典SQL查询 常用SQL查询: 1、查看表空间的名称及大小 selectt.tablespace_name, round(sum(bytes/(1024*1024)),0) ts_sizefromdba_tablespaces t, dba_data_files dwheret.tablespace_name = d.tablespace_name_用oracle sql语句 查询 热门t

随便推点

vue中的复用问题_vue页面复用按钮无效-程序员宅基地

文章浏览阅读826次。<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</titl..._vue页面复用按钮无效

使用过滤器(Filter)解决请求参数中文乱码问题(复杂方式)_增加过滤器后中文变成了ascii-程序员宅基地

文章浏览阅读2.5k次。前述: 在写这篇笔记之前,对笔记中的设计模式进行介绍: 本篇笔记中将要使用到的设计模式是:装饰(包装)设计模式 (1)装饰(包装)设计模式口诀: ①定义一个类,实现被装饰对象的接口 ②定义一个成员变量,记住被装饰对象的引用 ③定义构造_增加过滤器后中文变成了ascii

业务交付-SIT报告模板-程序员宅基地

文章浏览阅读819次,点赞13次,收藏8次。SIT报告

Xcode10版本升级后之library not found for -lstdc++.6.0.9报错-程序员宅基地

文章浏览阅读413次。最近Xcode版本升级到10之后,运行项目时出现library not found for -lstdc++.6.0.9错误。项目中有用到libstdc++、libstdc++.6、libstdc++6.0.9这三个库文件的Xcode10谨慎更新报错原因是:使用之前的Xcode版本开发的项目中有用到libstdc++、libstdc++.6、libstdc++6.0.9这三个库文件,而Xcod..._-lstdc++.6.0.9

使用taro自定义微信小程序导航栏_taro navigationstyle-程序员宅基地

文章浏览阅读2.2k次。1.在app.config.js中的window配置项的内容替换为:"navigationStyle":"custom"custom表示自定义导航栏,但会保留右上角胶囊按钮。window: { // backgroundTextStyle: 'light', // navigationBarBackgroundColor: '#fff', // navigationBarTitleText: 'WeChat', // navigationBarTextStyle: _taro navigationstyle

一文搞懂Transformer自注意力机制(图文代码详解)_transformer 自注意力机制-程序员宅基地

文章浏览阅读1.1k次,点赞21次,收藏13次。本系列文章致力于用最简单的语言讲解Transformer架构,帮助朋友们理解它的强大,本文是第六篇:Transformer自注意力机制图文详解。_transformer 自注意力机制

推荐文章

热门文章

相关标签