使用 $fetch 和 Pinia 的 Nuxt 3 JWT 身份验证

2024-02-06

我正在尝试对不同的 API 进行 JWT 身份验证。

由于 @nuxtjs/auth-next 似乎不是最新的,而且据我所知,可以在 Nuxt 3 中使用新的全局方法 fetch 而不是 @nuxtjs/axios (也不是最新的),我认为它自己编写身份验证代码不会太难!但这对我来说仍然是个谜,我只找到了 Vue 项目的文档(使用 Pinia 来保持用户登录),我有点迷失了。

我想实现的目标:

  • 包含电子邮件和密码的登录页面,登录请求发送到 API(编辑:完成!)
  • 从 API 获取 JWT 令牌和用户信息(编辑:完成!)并存储两者(即使页面刷新也保持用户记录)
  • 将 JWT 令牌全局设置为标头 $fetch 请求(?),这样我就不必将其添加到每个请求中
  • 如果用户未登录,则不允许访问其他页面

对此有什么帮助吗?

这是我的 login.vue 页面(之后我必须使用 Vuetify 和 vee-validate,但还是一次一步!)

// pages/login.vue
<script setup lang="ts">
import { useAuthStore } from "~/store/auth";

const authStore = useAuthStore();

interface loginForm {
  email: string;
  password: string;
}

let loginForm: loginForm = {
  email: "",
  password: "",
};

function login() {
  authStore.login(loginForm);
}
</script>

<template>
  <v-container>
    <form @submit.prevent="login">
      <label>E-mail</label>
      <input v-model="loginForm.email" required type="email" />
      <label>Password</label>
      <input v-model="loginForm.password" required type="password" />
      <button type="submit">Login</button>
    </form>
  </v-container>
</template>

目前是 store/auth.ts。

// store/auth.ts
import { defineStore } from 'pinia'
import { encodeURL } from '~~/services/utils/functions'

export const useAuthStore = defineStore({
  id: 'auth,
  state: () => ({
    // TODO Initialize state from local storage to enable user to stay logged in
    user: '',
    token: '',
  })
  actions: {
    async login(loginForm) {
      const URL_ENCODED_FORM = encodeURL({
        email: loginForm.email,
        password: loginForm.password,
      });
      return await $fetch('api_route', {
        headers: {
          "Content-Type": "application/x-www-form-urlencoded"
        },
        method: 'POST',
        body: URL_ENCODED_FORM
      }
    } 
  }
})

为了完整起见,我将分享所有内容,甚至是您标记为已完成的部分。

首先,您需要在后端生成 JWT,您可以在没有任何包的情况下简单地执行此操作,但我建议这个包 https://github.com/auth0/node-jsonwebtoken为了那个原因。另外,我将使用 objection.js 来查询数据库,即使您不知道 objection.js 也应该很容易理解

您的登录视图需要像这样发送登录尝试请求

const token = await $fetch('/api/login', {
    method: 'post',
    body: {
      username: this.username,
      password: this.password,
    },
  });

就我而言,它请求 /server/api/ 中的 login.post.ts

import jwt from 'jsonwebtoken';
import { User } from '../models';

export default defineEventHandler(async (event) => {
  const body = await useBody(event);
  const { id } = await User.query().findOne('username', body.username);
  const token: string = await jwt.sign({ id }, 'mysecrettoken');
  return token;
});

为了简单起见,我在这里没有查询密码,这取决于您如何生成用户密码。 “mysecrettoken”是您的用户永远不应该知道的令牌,因为他们可以像其他人一样登录。当然这个字符串可以是任何你想要的字符串,越长越好。

现在您的用户获得一个令牌作为响应,应该只是一个简单的字符串。我稍后会写一篇关于如何保存这个以供将来请求的文章。

要使用此令牌发出经过身份验证的请求,您将需要执行如下请求:

$fetch('/api/getauthuser', {
            method: 'post',
            headers: {
              authentication: myJsonWebToken,
            },
          });

我更喜欢添加一个中间件来更轻松地访问我的 api 端点中的经过身份验证的用户。该中间件名为 setAuth.ts,位于 server/middleware 文件夹内。它看起来像这样:

import jwt from 'jsonwebtoken';

    export default defineEventHandler(async (event) => {
      if (event.req.headers.authentication) {
        event.context.auth = { id: await jwt.verify(event.req.headers.authentication, 'mysecrettoken').id };
      }
    });

其作用是验证是否传递了身份验证标头,它检查令牌是否有效(使用与您签署 jwt 的相同秘密令牌),如果有效,则将 userId 添加到请求上下文以便于端点访问。

现在,在我的 server/api/getauthuser.ts 端点中可以像这样获取 auth 用户

import { User } from '../models';

export default defineEventHandler(async (event) => {
  return await User.query().findById(event.context.auth.id)
});

由于用户无法设置请求上下文,因此您可以确定您的中间件设置了此 auth.id

您现在已经有了基本的身份验证。

我们生成的令牌具有无限的生命周期,这可能不是一个好主意。如果此令牌暴露给其他人,他们将无限期地拥有您的登录信息,进一步解释将超出此答案的范围。

您可以将身份验证令牌保存在 localStorage 中,以便在下一个页面加载时再次访问它。有些人认为这是一种不好的做法,并且更喜欢使用 cookie 来存储它。我会保持简单并使用 localStorage 。

现在,对于用户不应访问登录以外的页面的部分:我在 middleware/auth.global.ts 中设置了一个全局中间件(您也可以执行一个非全局中间件并为特定页面指定它) auth.global.ts 看起来像这样:

import { useAuthStore } from '../stores';

export default defineNuxtRouteMiddleware(async (to) => {
  const authStore = useAuthStore();

  if (to.name !== 'Login' && !localStorage.getItem('auth-token')) {
    return navigateTo('/login');
  } else if (to.name !== 'Login' && !authStore.user) {
    authStore.setAuthUser(await $fetch('/api/getauthuser', {
      headers: authHeader,
    }));
  }
});

我使用 pinia 将身份验证用户存储在我的 authStore 中,但前提是本地存储中有身份验证令牌 (jwt)。如果有且尚未获取,请通过 getauthuser 端点获取 auth 用户。如果没有 authtoken 并且该页面不是登录页面,则将用户重定向到该页面

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 $fetch 和 Pinia 的 Nuxt 3 JWT 身份验证 的相关文章

  • 无需代理转发的 SSH 跳转主机

    虽然是一个简单的问题 但我已经搜索了几天没有成功 M My machine J Jump Host S Server Jump Host has my public key on authorized keys Server has J s
  • Django:登录用户并在同一页面上刷新而不定义模板?

    我正在尝试使用引导下拉登录表单来让用户登录 我可以对我的用户名和密码进行硬编码并进行身份验证 但我试图在不进入登录屏幕的情况下让用户登录 这是我的代码 模板 我使用操作来调用 logUserIn url 以便表单可以发布到该视图 ul cl
  • Windows 身份验证到底如何工作? web.config 似乎不够

    正在尝试修复 Windows 身份验证 目标 Windows 身份验证 使用 Firefox 时 应出现登录对话框 而使用 Internet Explorer 时 Windows 用户名和密码应自动转到 Web 服务器 我使用空模板建立了一
  • Laravel - JWT Auth 无法从请求中解析令牌

    我在中间件中添加了以下代码以进行用户身份验证JWT Auth https github com tymondesigns jwt auth 它适用于中间件处理的所有路由 public function handle request Clos
  • 如何正确处理 JWT 刷新?

    我有一个安卓应用程序 它连接到一个REST API开发与Jersey 我的 REST 端点通过令牌进行保护 下面是我生成它们的方法 Algorithm algorithm Algorithm HMAC256 secret String to
  • 自定义用户返回空 get_all_permissions()

    我只是想开始工作Permissions了解这是如何工作的 在外壳中我有空set 结果来自user test get all permissions I see 这个问题 https stackoverflow com questions 2
  • Android Facebook SDK 4.5.0 登录注销问题,尝试再次登录时出现无效密钥哈希错误

    我按照中所述实现了 Facebook 登录按钮https developers facebook com docs facebook login android https developers facebook com docs face
  • 如何向 Scotty 中间件添加基本身份验证?

    我目前正在制作 Scotty API 但找不到任何 basicAuth 实现的示例 Wai Middleware HttpAuth 具体来说 我想将基本身份验证标头 用户 通行证 添加到我的某些端点 即以 admin 开头的端点 我已经设置
  • 如何同时模拟Pinia和vue-i18n?

    我正在使用 Vue 3 的 Composition API 如下所示 store ts import ref Ref from vue import defineStore from pinia export const useStore
  • 当角度4中令牌过期时如何重定向到注销

    我有一个 Angular 4 应用程序 我在那里使用 JWT 令牌进行身份验证 一切正常 但我给 JWT 令牌的令牌过期时间是 1 小时 一旦服务器端的令牌过期 我想从前端应用程序中注销用户 在节点后端 我使用快速中间件通过检查所有请求是否
  • Polymer 1.0:用户身份验证 UX(建议、教程和示例)?

    是否有推荐的 聚合物方式 来进行用户身份验证 这个问题包括技术部分和用户体验 用于进行用户身份验证的用户体验的全面示例 和 或教程 将非常棒 注意 Polymer 入门套件不包含任何身份验证 UX 示例 在这个问题中 用户体验 的意思是 完
  • 我可以在 psycopg2 中使用 md5 身份验证吗?

    经过两个小时的阅读文档 源代码和帮助线程后 我放弃了 我无法让 psycopg2 使用 md5 字符串进行身份验证 根据this http bytes com topic python answers 42597 psycopg authe
  • 如何使用多重身份验证 - firebase?

    我有一个注册屏幕 其中包含 用户名 电子邮件 电话号码 密码 在本例中 我使用电话号码身份验证来验证号码 因此在用户验证他的号码后 我将他的数据保存到 firebase DB 中 所以在那之后 我将下摆导航到登录屏幕 应该包含电子邮件 密码
  • 请确保至少一个领域可以验证这些令牌

    所以我把我的shiro设置为有两个Realms 用户名和密码领域 使用标准 UsernamePasswordToken 我还设置了一个自定义承载身份验证令牌 用于处理从用户传入的令牌 如果我只使用我的passwordValidatorRea
  • SharePoint Online 身份验证失败

    我有一个 C 应用程序 它通过使用 Web 请求对 SharePoint Online 进行身份验证 它对我来说非常有用 但其他人收到以下错误
  • 在哪里存储角度中的 JWT 令牌?

    我正在使用 Django 和 Angular 构建一个应用程序 目前 我正在本地存储上存储后端发出的 JWT 但是 我担心 XSS 攻击 我应该使用仅 HTTP 的 cookie 来存储令牌吗 我还考虑将令牌存储在我的身份验证服务类中的变量
  • 不知道如何预览我生成的 Nuxt3 应用程序

    我刚刚在静态模式下创建了一个 Nuxt3 但我不想每次都将其推送到 Netlify 进行预览 这是我的nuxt config js 没有改变 import defineNuxtConfig from nuxt export default
  • Asp.net Identity 注销其他用户

    我正在使用 Asp net Identity 来验证用户身份 并尝试从管理端锁定任何用户 但是当我锁定任何在线用户时 它并没有注销 我读过很多关于我的问题的评论 但它们都不起作用 我尝试使用 UserManager UpdateSecuri
  • iOS 相互认证

    我正在尝试在 IOS 5 中实现相互身份验证 但遇到了麻烦 NSUnderlyingError Error Domain kCFErrorDomainCFNetwork Code 1200 An SSL error has occurred
  • 使用自定义 AuthenticationScheme 的 Blazor 服务器 cookie 身份验证

    我正在尝试在我的 Blazor 服务器应用程序中构建自定义 cookie 身份验证 只要我像这样使用 DefaultAuthenticateScheme 它就可以工作 builder Services AddAuthentication o

随机推荐

  • BCC 发送 PHP mail() 到邮件列表的方式与 TO 不同吗?

    我正在改进 PHP 邮件列表代码 使用mail 在循环中迭代所有订阅者 该脚本用于显示 超出最大执行时间 30 秒 错误 我通过添加解决了该错误set time limit 0 现在没有错误 但发送 100 条消息花了大约七分钟 我有什么选
  • 如何了解System.Windows.Forms.dll中System.InvalidOperationException的详细信息?

    运行我的应用程序时 我在 Visual Studio 的 输出 面板中发现了下面的异常日志 System Windows Forms dll 中发生 System InvalidOperationException 类型的第一次机会异常 该
  • 动态像素化 html 图像元素

    我要在网页上拍摄图像 然后使用 javascript 或最适合的任何内容 对其进行动态 像素化 例如 变成 20px 的正方形 然后 当用户向下滚动页面时 我需要图像的分辨率逐渐增加 直到它不再像素化 我有什么想法可以去做这件事吗 我意识到
  • PayPal Express Checkout 集成响应

    我目前很难理解我的 PayPal EC 集成的响应 GetExpressCheckoutDetails 响应是 CHECKOUTSTATUS gt PaymentActionNotInitiated 但在 DoExpressCheckout
  • WPF设计问题(自定义控件或mvvm)

    这是场景 我有一个显示一些数据的视觉效果 The data to the visual can come in one of two ways 通过用户通过键盘或鼠标输入 通过一些后端源 Both these data inputs can
  • WooCommerce 上的购物车总重量和运输重新计算

    我正在尝试使用一个片段将我的自定义盒子重量添加到总订单重量中 目前工作正常 但是 不会根据重新计算的片段重量重新计算运输方式 有什么想法如何强制重新计算运费吗 add filter woocommerce cart contents wei
  • 完全删除 MySQL 5.7 [关闭]

    Closed 这个问题是无关 help closed questions 目前不接受答案 我正在尝试从 ubuntu 12 04 中完全卸载 mysql 但没能做到 我尝试了很多命令 但没有任何作用 任何人都可以帮忙吗 sudo apt g
  • 用于对基于时间的值进行排序的 Redis 数据结构设计

    我正在对数据流执行一些分析并将结果发布到 Redis 通道上 消费者订阅这些频道并获取实时数据源 所有历史数据分析结果都会丢失 现在我想添加在Redis中存储历史数据的能力 以便消费者可以查询这些历史数据 主要是按时间 由于分析结果按时间分
  • 如何在一项任务中执行多个 gulp 命令

    我很难理解如何在单个任务中处理多个 gulp 源 在这样的任务中 gulp task task1 function cb gulp src src js pipe gulp dest dist gulp src src css pipe g
  • 如何将 Linux shell 脚本编译为独立的可执行文件*二进制*(即不仅仅是 chmod 755)?

    我正在寻找一个免费的开源工具集 可以编译各种 经典 脚本语言 例如Korn Shell ksh csh bash 等作为可执行文件 如果脚本调用其他程序或可执行文件 则将它们包含在单个可执行文件中 Reasons 混淆交付给客户的代码 以免
  • 快速修复/n 错误:MsgSeqNum 太高

    我已经使用 QuickFIX n is v1 4 0 从此 创建了一个修复应用程序 http www quickfixn org download http www quickfixn org download 地点 当我执行应用程序时 我
  • 反序列化 xml,包括命名空间

    我正在尝试反序列化一些 XML 但无法获取名称空间 xsi type Model 上班 如果xsi type Model 被排除在 XML 之外 它可以工作 但它必须存在 如果我将命名空间保留在模型之外 则会收到错误 如果重命名它 则会得到
  • AngularJS 拦截并扩展控制器 $scope

    我在应用程序中定义了许多可重用的功能 每个控制器都与 scope 变量一起使用 有没有办法扩展 scope 变量 以便我可以在任何地方使用我的扩展代码 而不是每次都创建共享服务 就像是 I ve tested this out and it
  • 我希望我的 Android 应用程序仅在纵向模式下运行?

    我希望我的 Android 应用程序仅在纵向模式下运行 我怎样才能做到这一点 在清单中 为您的所有活动进行设置
  • PyDev 的导入错误

    我使用 PyDev Eclipse 已有几个月了 并且在导入时遇到了相同的错误 PyDev 在导入中用红色下划线并说Unresolved import xxx Found at yyy 当我点击yyyeclipse找到并打开该模块的执行 P
  • 安装了jSweet。怎么办?

    我有一个java项目 我想将其转换为Typescript 大约150个文件 As per http www jsweet org getting started http www jsweet org getting started 我查看
  • iPhone开发配置助手第3步公钥/私钥问题

    您好 我正在使用开发配置助手 在第 3 步 在 钥匙串访问 中验证您的私钥和公钥时 我在 钥匙串 gt 登录 中有 iPhone 开发人员 XXXXXXX 证书 但找不到任何密钥 如果我单击 类别 gt 键 我什么也看不到 我应该怎么做才能
  • Windows批处理脚本仅保留目录中的N个最新文件夹

    我有一个目录 我将 MySQL 数据库备份到具有当前日期的文件夹中 现在 30 或 60 天后 我喜欢只保留该备份目录中的 n 个最新文件夹 并删除其余文件夹 每个文件夹中都有 gzip 压缩的数据库 为了备份我使用的 MySQL 数据库a
  • QWebPage多次触发loadFinished()

    我正在使用 load 方法将内容加载到 QWebPage 中 但我的 loadStarted loadFinished 和 loadProgress 处理程序调用了多次 如何检测该页面已完全加载其所有内容 在以下位置发布了相关解决方案提案
  • 使用 $fetch 和 Pinia 的 Nuxt 3 JWT 身份验证

    我正在尝试对不同的 API 进行 JWT 身份验证 由于 nuxtjs auth next 似乎不是最新的 而且据我所知 可以在 Nuxt 3 中使用新的全局方法 fetch 而不是 nuxtjs axios 也不是最新的 我认为它自己编写