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

Spring OAuth2社交登录与NUXT 3客户端集成及令牌管理问题

解决方案:Nuxt3 + Spring OAuth2 社交登录集成

一、认证状态管理:Pinia 是优先选择

别纠结自定义组合式函数了,直接用Pinia——它是Nuxt3官方推荐的状态管理方案,自带成熟的持久化插件,能帮你轻松搞定令牌、用户角色的跨页面存储,不用自己写本地存储逻辑,调试起来也更方便。

示例Pinia Store代码:

// stores/auth.ts
import { defineStore } from 'pinia'

export const useAuthStore = defineStore('auth', {
  state: () => ({
    accessToken: null,
    userInfo: null,
    roles: []
  }),
  actions: {
    setAuthData(token, user, roles) {
      this.accessToken = token
      this.userInfo = user
      this.roles = roles
    },
    clearAuthData() {
      this.accessToken = null
      this.userInfo = null
      this.roles = []
    }
  },
  persist: true // 自动持久化到localStorage,刷新不丢状态
})

二、令牌处理:别直接从URL硬提

你现在从route.query.token拿令牌的方式太直白,还容易暴露敏感信息。优化方案分两种:

  1. 推荐用授权码模式:让Spring OAuth2返回授权码,前端拿授权码去后端换令牌(授权码是一次性的,比直接返回令牌安全)
  2. 如果后端只能用隐式模式返回令牌:拿到后立刻清理URL参数,同时验证令牌有效性

示例Nuxt插件处理逻辑:

// plugins/auth-handler.ts
export default defineNuxtPlugin(async (nuxtApp) => {
  const authStore = useAuthStore()
  const route = useRoute()
  const router = useRouter()

  nuxtApp.hook('page:finish', async () => {
    const token = route.query.access_token
    if (token && !authStore.accessToken) {
      // 先调用后端接口验证令牌,顺便拉取用户角色
      const { data: userData } = await useFetch('/api/auth/user-info', {
        headers: { Authorization: `Bearer ${token}` }
      })
      
      if (userData.value) {
        authStore.setAuthData(token, userData.value, userData.value.roles)
        // 清理URL里的令牌参数,避免泄露
        await router.push({ path: route.path, query: {} })
      }
    }
  })
})

三、全局请求拦截:自动带令牌

封装一个全局请求函数,自动给所有接口加上Authorization头,同时处理令牌过期:

// composables/useApi.ts
export const useApi = () => {
  const authStore = useAuthStore()
  return $fetch.create({
    baseURL: '/api',
    onRequest({ options }) {
      // 请求前自动注入令牌
      if (authStore.accessToken) {
        options.headers.Authorization = `Bearer ${authStore.accessToken}`
      }
    },
    onResponseError({ response }) {
      // 令牌过期/无效时清空状态并跳转登录页
      if (response.status === 401) {
        authStore.clearAuthData()
        navigateTo('/login')
      }
    }
  })
}

四、角色权限控制

用Pinia的状态封装权限判断函数,在页面/组件里直接用:

// composables/useAuthCheck.ts
export const useAuthCheck = () => {
  const authStore = useAuthStore()
  return {
    hasRole: (role: string) => authStore.roles.includes(role),
    isLoggedIn: () => !!authStore.accessToken
  }
}

页面中使用示例:

<script setup>
const { hasRole } = useAuthCheck()
</script>

<template>
  <button v-if="hasRole('ADMIN')">管理员操作按钮</button>
</template>

内容的提问来源于stack exchange,提问作者Oz Shemesh

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 04:00:07