Laravel + SSR nuxt: 如何保存登录状态

基于 Laravel + Nuxt3 的在线 Demo

Laravel + 客户端渲染的 Vue 确实写起来比较快,但是我们有些时候确实很需要 SEO,比如说电商、门户网站、论坛;而且对于大型项目,相比起客户端渲染,服务器端渲染带来的首屏加载时间上的优势确实是碾压的。

但是很多同学卡在了 SSR下如何保存登录状态 这个问题下面,即如何像传统的 PHP/JSP 页面那样,刷新页面后仍保有登录状态


准备工作

首先准备 2 个接口,一个是

GET http://example.com/api/auth/user

用户获取当前登录用户信息

POST http://example.com/api/auth/tokens

用于请求授权

这里有一个包含 GitHub OAuth 的完整例子 👉 laravel-nuxt3-api,并且测试覆盖率是 100%
Laravel + SSR nuxt: 如何保存登录状态


开始 SSR

  • Nuxt3

Nuxt3 中,可以很自由地创建一个 server only 的脚本,在 initial 整个 Nuxt App 时,可以在渲染 html 前执行这个 server only 的脚本,并在渲染 html 时使用其返回的结果。

我们可以在 plugins 下面创建一个 *.server.[js|ts] 的 server only 的脚本,

plugins/init.server.js

import { defineNuxtPlugin } from '#app'; import { useAuth } from '~/store/auth.js'; function cookieFromRequestHeaders (key) { const headers = useRequestHeaders(['cookie']); if ('cookie' in headers) { const cookie = headers.cookie.split(';').find( c => c.trim().startsWith(`${key}=`) ); if (cookie) { return cookie.split('=')[1]; } } return ''; } export default defineNuxtPlugin(async (nuxtApp) => { const token = cookieFromRequestHeaders('token'); if (token) { const auth = useAuth(nuxtApp.$pinia); auth.setToken(token); await auth.fetchUser(); } });

store/auth.js 定义管理全局状态的 pinia,并在其中发送异步请求

import { defineStore } from 'pinia'; import { useCustomFetch } from '~/composables/useCustomFetch.js'; import cookie from 'js-cookie'; export const useAuth = defineStore('auth', { state: () => ({ _token: '', _user: {}, }), getters: { token() { return this._token; }, user() { return this._user; }, }, actions: { async fetchUser() { const { data, error } = await useCustomFetch('/auth/user'); if (error.value) { this.reset(); } else { this.setUser(data.value); } }, // ... }, });

注意: Nuxt3 中不推荐使用 axios 等第三方的 http 包,而是使用其内置的 useFetch()

完整的例子 👉 laravel-nuxt3-web

  • Nuxt2

Nuxt2 中,不同于 Nuxt3,Nuxt2 只能在 store/index.js 中的 nuxtServerInit() 中运行 server only 的脚本(但是这里我们可以使用 axios)

store/index.js

export const actions = { nuxtServerInit({ commit, dispatch, route }, { req }){ const token = cookieFromRequest(req, 'token'); if (!!token) { commit('auth/setToken', token); } } };

store/auth.js

import Cookie from 'js-cookie'; export const state = () => ({ user: null, token: null }); export const getters = { user: state => state.user, token: state => state.token, check: state => state.user !== null }; export const mutations = { setToken(state, token){ state.token = token; }, fetchUserSuccess(state, user){ state.user = user; }, fetchUserFailure(state){ state.user = null; }, logout(state){ state.token = null; state.user = null; }, updateUser(state, { user }){ state.user = user; } } export const actions = { saveToken({ commit }, { token, remember }){ commit('setToken', token); Cookie.set('token', token); }, async fetchUser({ commit }){ try{ const { data } = await this.$axios.get('/auth/user'); commit('fetchUserSuccess', data); }catch(e){ Cookie.remove('token'); commit('fetchUserFailure'); } }, // ... }

更完整的代码 👉 Nuxt middleware to check if user is logged in not working

本作品采用《CC 协议》,转载必须注明作者和本文链接
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!