所有分类
  • 所有分类
  • Html5资源
  • React资源
  • Vue资源
  • Php资源
  • ‌小程序资源
  • Python资源

Nuxt JWT认证全攻略 – 从零实现安全登录系统

Nuxt 是什么?

Nuxt 是一个基于Vue 3的服务器端渲染(SSR)框架,它继承了Nuxt.js的核心概念,并利用Vue 3的最新特性,如组合式API(Composition API)和<script setup>语法,来提供更加现代化的开发体验。

Nuxt 的关键特性

  • 性能优化:Nuxt 在性能方面做了很多优化,例如服务器端渲染(SSR)、预渲染(prerendering)等
  • 模块化:基于Vue.js的模块化架构
  • 自动化:内置自动化代码生成、热重载、单元测试等功能
  • 支持所有渲染模式:SSR、CSR、SSG
  • 基于Vue 3的高性能开发
  • 高度集成Vite、Vue Router等实用库
  • 更轻、更快的部署
  • 混合型渲染能力
  • 支持Suspense
  • 组合式API
  • Nuxt CLI
  • Nuxt 开发工具
  • Nuxt Kit
  • webpack 5
  • Vite支持
  • TypeScript原生支持

JWT Token 签发与校验实现

开发一个网页端的项目,系统登录是必不可少的功能。下面我们将实现一个简单的登录token签发&校验接口。

技术栈准备

  • Nuxt 3
  • Prisma
  • MySQL

1. 实现Prisma数据模型

model User {
  id       Int    @id @default(autoincrement())
  userName String @unique
  password String
}

2. Prisma实例配置

import { PrismaClient } from "@prisma/client";

const prismaClientSingleton = () => {
  return new PrismaClient({
    omit: {
      sys_user: {
        password: true // 全局屏蔽password字段返回
      }
    }
  });
};
type PrismaClientSingleton = ReturnType<typeof prismaClientSingleton>;

const globalForPrisma = globalThis as unknown as {
  prisma: PrismaClientSingleton | undefined;
};

const prisma = globalForPrisma.prisma || prismaClientSingleton();

export default prisma;

if (process.env.NODE_ENV !== "production") globalForPrisma.prisma = prisma;

3. 密码加密存储

使用crypto-js模块进行MD5加密:

import CryptoJS from 'crypto-js';

const MD5_KEY = 'ifrontend.net';

export const encryptAES = (value: string) => {
  if (value == '') return '';
  const keyHex = CryptoJS.enc.Utf8.parse(MD5_KEY);
  const encrypted = CryptoJS.AES.encrypt(value, keyHex, {
    mode: CryptoJS.mode.ECB,
    padding: CryptoJS.pad.Pkcs7,
  });
  return encrypted.toString();
}

4. JWT 签发与校验

使用jsonwebtoken实现:

import jwt from 'jsonwebtoken';

const secretKey = 'ifrontend.net';

export const signToken = (username: string, expiresIn: string = '1h') => {
  return jwt.sign({ username }, secretKey, { expiresIn });
}

export const verifyToken = (token: string) => {
  try {
    const decoded = jwt.verify(token, secretKey);
    return decoded;
  } catch (err) {
    return null;
  }
}
import prisma from '@/server/lib/prisma';
import { encryptAES } from '@/server/lib/md5';
import { signToken } from '@/server/lib/jwt';

export default defineEventHandler(async (event) => {
  try {
    const body = await readBody(event);
    const { userName, password } = body;

    const user = await prisma.User.findMany({
      where: {
        userName,
        password: encryptAES(password),
      },
    });

    if (!user) {
      return {
        code: 200,
        msg: '用户名或者密码有误',
      };
    } else {
      return {
        code: 200,
        msg: '登录成功',
        data: signToken(userName),
      }
    }
  } catch (error) {
    throw error;
  } finally {
    await prisma.$disconnect(); // 关闭连接
  }
})

Token失效时间说明

  • 支持格式:”2 days”, “10h”, “7d”
  • 数值表示秒数
  • 必须明确指定时间单位,否则默认为毫秒

6. 权限校验中间件

Nuxt 的服务器中间件可以自动拦截请求进行权限校验:

// auth.ts
import { verifyToken } from '@/server/lib/jwt';

export default defineEventHandler((event) => {
  // 无需校验的token权限的服务
  const notAuthUrls = [
    '/api/user/login',
  ];
  const currentUrl = event.node.req.url;

  if (!notAuthUrls.includes(currentUrl as string)) {
    // 获取headers
    const headers = getHeaders(event);
    const authorization = headers['authorization'] as string;
    if (authorization) {
      const token = authorization.split(' ')[1];
      if (!verifyToken(token)) {
        return {
          code: 403,
          msg: '登录失效'
        }
      }
    } else {
      return {
        code: 404,
        msg: '无权限'
      }
    }
  }
})

权限校验效果

  • 无权限接口:返回403或404状态码
  • 有权限接口:正常访问

扩展阅读

原文链接:https://code.ifrontend.net/archives/984,转载请注明出处。
0

评论0

显示验证码
没有账号?注册  忘记密码?