You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Nuxt3中如何在Pinia Store配置Cookie并监听过期刷新令牌

Nuxt3 + Pinia 实现Cookie过期自动刷新Token

一、替换存储方式为Cookie

原代码用useStorage默认存在localStorage,要改成Cookie并设置过期时间,推荐用Nuxt3内置的useCookie(和@vueuse/core的useCookie用法兼容)。修改Pinia的state定义:

import { defineStore } from "pinia";
import repo from "~/repositories/index";
import { getUserImage } from "~/utils/helperFunctions";
import { useCookie } from "#app"; // 引入Nuxt内置Cookie工具

export const useUserStore = defineStore("user-store", {
    state: () => ({
        email: useCookie("email", { default: "", maxAge: 0 }),
        img_url: useCookie("img_url", { default: "", maxAge: 0 }),
        refreshToken: useCookie("refreshToken", { default: "", maxAge: 86400 * 7 }), // 刷新Token有效期设为7天(按需调整)
        bearerToken: useCookie("bearerToken", { default: "", maxAge: 0 }),
        expiryIn: useCookie("expiryIn", { default: 0, maxAge: 0 }),
        domains: useCookie("domains", { default: [], maxAge: 0 }),
        refreshTimer: null as NodeJS.Timeout | null, // 存储定时器ID,用于后续清除
    }),

二、新增Token刷新Action

在actions中添加refreshToken方法,负责调用后端接口获取新Token并更新状态:

async refreshToken() {
    try {
        if (!this.refreshToken) return;
        const data = await repo.user.refreshToken(this.refreshToken);
        if (data) {
            // 更新Token和有效期
            this.bearerToken = data.bearerToken;
            this.expiryIn = data.expiryIn;
            // 同步更新Cookie的过期时间
            this.bearerToken.options.maxAge = data.expiryIn;
            this.expiryIn.options.maxAge = data.expiryIn;
            // 重新设置刷新定时器
            this.setRefreshTimer();
        } else {
            // 刷新失败,执行登出
            this.logOut();
        }
    } catch (error) {
        console.error("[UserStore] [RefreshToken] 刷新失败:", error);
        this.logOut();
    }
},

三、登录后设置过期定时器

登录成功后,根据返回的expiryIn(秒数)设置定时器,提前30秒触发刷新(避免刚好过期时请求失败):

async login(email: string, password: string) {
    try {
        const data = await repo.user.login(email, password);
        if (data != null) {
            // 原有状态赋值逻辑保留
            this.$state.email = email;
            this.$state.img_url = getUserImage(email);
            this.$state.bearerToken = data.bearerToken;
            this.$state.expiryIn = data.expiryIn;
            this.$state.refreshToken = data.refreshToken;
            this.$state.domains = data.domains;

            // 同步设置所有用户相关Cookie的过期时间
            const cookieMaxAge = data.expiryIn;
            this.email.options.maxAge = cookieMaxAge;
            this.img_url.options.maxAge = cookieMaxAge;
            this.bearerToken.options.maxAge = cookieMaxAge;
            this.expiryIn.options.maxAge = cookieMaxAge;
            this.domains.options.maxAge = cookieMaxAge;

            // 设置刷新定时器
            this.setRefreshTimer();

            return true;
        } else {
            console.log("[UserStore] [Login] 登录失败");
            return false;
        }
    } catch (error) {
        console.log("[UserStore] [Login] 错误:", error);
        return false;
    }
},
// 封装定时器设置逻辑
setRefreshTimer() {
    // 清除已有定时器,避免重复触发
    if (this.refreshTimer) {
        clearTimeout(this.refreshTimer);
    }
    // 计算延迟时间:提前30秒刷新,转毫秒单位
    const refreshDelay = (this.expiryIn - 30) * 1000;
    if (refreshDelay > 0) {
        this.refreshTimer = setTimeout(() => {
            this.refreshToken();
        }, refreshDelay);
    }
},

四、页面加载时检查Token状态

在Nuxt插件中初始化Store时,检查Token是否即将过期,自动触发刷新:

在plugins/user-store.ts中添加:

import { useUserStore } from "~/stores/user-store";

export default defineNuxtPlugin((nuxtApp) => {
    const userStore = useUserStore(nuxtApp.$pinia);
    if (userStore.bearerToken && userStore.expiryIn) {
        // 计算剩余有效时间(需确保expiryIn是剩余秒数,若后端返回的是过期时间戳,需转换为剩余时间)
        const remainingTime = userStore.expiryIn;
        if (remainingTime < 30) {
            // 剩余时间不足30秒,直接刷新
            userStore.refreshToken();
        } else {
            // 设置定时器
            userStore.setRefreshTimer();
        }
    }
});

五、登出时清除定时器

修改logOut方法,清除定时器避免内存泄漏:

logOut() {
    console.log("[UserStore] [LogOut] 正在退出");
    // 清除刷新定时器
    if (this.refreshTimer) {
        clearTimeout(this.refreshTimer);
        this.refreshTimer = null;
    }
    // 原有状态清空逻辑保留
    this.$state.email = "";
    this.$state.img_url = "";
    this.$state.bearerToken = "";
    this.$state.expiryIn = 0;
    this.$state.refreshToken = "";
    this.$state.domains = [];
},

关键注意事项

  • 后端返回的expiryIn必须是秒数,因为Cookie的maxAge参数单位为秒。
  • 若后端返回的是Token过期时间戳(Unix时间),需转换为剩余时间:expiryTimestamp - Math.floor(Date.now() / 1000)。
  • 刷新Token的API需接受refreshToken作为参数,返回新的bearerToken和expiryIn。

内容的提问来源于stack exchange,提问作者Abdullah Sheikh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 00:29:50