【React(SPA) + Laravel】 确保在刷新浏览器后继续保持登录验证状态
技术的前提
・前端:使用React 18系 + TypeScript + Context
・後端:使用Laravel 8系 + Laravel Sanctum(作為SPA驗證)
使用React作为前端开发工具创建单页面应用(SPA)。
后端采用Laravel作为API服务器。
顺便问一下,Laravel Sanctum 是什么?
在最新的Laravel版本中,已经默认配置了与认证相关的中间件。
使用Sanctum可以轻松实现用户注册、登录等功能。
由于官方和各种文章都有使用这种登录方法,所以本文将省略详细介绍。
想做的事情
我将在React中实现用户注册和登录功能。
大致的注册和登录流程如下:
【1】用户通过React把邮箱和密码发送到后端(Laravel),如果能够验证成功,则返回用户信息。(注册用户时也是相同的流程)
※有关这部分的实现方法,请参考前面提到的参考文献等。
【2】在React中,接收到的用户信息将作为全局值保存。
由于不想在全局范围内保存大量信息,以下作为常见的内容,如果显示在标题栏部分,
“用户名称”
“user_id”
“登录状态”
是否已足够了呢?
(※其他详细信息(如电子邮件地址和出生日期等)可以通过用户ID逐页重新获取)


终于解决了问题。
以上的方法允许在React(单页面应用)+ Laravel环境中进行登录和会员注册。
然而,请注意React是通过单页面应用构建的。
当浏览器进行重新加载时,将会丢失已存储在上下文中的“名称”、“登录状态”、“ID”等信息。
当您在登录状态下使用链接标签进行页面跳转时,您可以正常保持登录状态。但是,如果您重新加载浏览器,或者关闭浏览器后直接打开链接,您的登录状态将会丢失。
关于spa,这里的解释比较易懂!
https://qiita.com/shinkai_/items/79e539b614ac52e48ca4
解决方案
在Sanctum中,有一个用于检查用户“登录状态”的中间件。
请在https://readouble.com/laravel/8.x/ja/sanctum.html的“路由保护”部分设置以下路由,然后通过从React向以下路由发送请求,
可以检查浏览器本身的登录授权状态,并在登录状态下返回用户信息。
//こちらをroutesのapi.phpに記述
Route::middleware('auth:sanctum')->get('/user', function (Request $request) {
return $request->user();
});
关于Sanctum的登录状态,通过在通信中携带具有专门信息的唯一的cookie,如果浏览器的通信中有该cookie,则进行认证。
※基本上使用以下laravel标准认证功能的方式。
https://readouble.com/laravel/master/ja/authentication.html
因此,只需要在应用程序的开头检查一次“用户是否已登录到浏览器”的状态,就可以在重新加载时再次进行登录检查。(这次我们将其用于上下文。)
具體的調整內容(程式碼記述內容)
◼ Laravel的api路由
//前述のコード
Route::middleware('auth:sanctum')->get('/user', function (Request $request) {
return $request->user();
});
◼React端
函数的定义
◼React侧
函数的定义
◼React端口
函数定义
import axios, { AxiosResponse } from "axios";
/**
* ブラウザリロード時に利用。関数定義がわ
*/
export const LogInCheck = ():Promise<AxiosResponse> =>{
axios.get(
'サーバーurl/sanctum/csrf-cookie',
{ withCredentials: true }) // CSRFトークンの初期化
const response = axios.get(
'サーバーurl/user',
{withCredentials:true}
)
return response;
}
定义提供者(文件位置等可选)
import {useState,createContext,useEffect} from "react";
//型定義
//ここでは名前、ログイン有無、user_idだけ渡します。)
type LoggedInContextType ={
setUserAuth:(value:boolean) => void;
setUserID: (value: number) => void;
setUserName: (value: string) => void;
userAuth:boolean;
userid: number;
username: string;
}
export const LoggedInContext = createContext<LoggedInContextType>({} as LoggedInContextType);
//認証情報とセットするコンテキスト
export const LoggedInProvider = (props) => {
const { children } = props;
// globalなstateのデフォルトの値を作成
const [username, setUserName] = useState<string>('');
const [userid, setUserID] = useState<number>(0);
const [userAuth, setUserAuth] = useState<boolean>(false);
//初回だけ、ログインチェックを行う
useEffect(()=>{
LogInCheck().
then((res) => {
setUserName(res.data.name);
setUserID(res.data.user_id);
setUseremail(res.data.email);
setUserAuth(true);
})
},[])
return (
<LoggedInContext.Provider value={{username,setUserName,userid,setUserID,userAuth,setUserAuth}}>
{children}
</LoggedInContext.Provider>
)
}
通过在这里使用提供者,可以在整个路由中仅进行一次登录检查的大元应用定义。
App.tsx 文件
import { BrowserRouter } from "react-router-dom";
import { MainRoute } from "../src/router/MainRoute";
import { LoggedInProvider} from "./provider/LoggedInProvider";
function App() {
return (
<>
<BrowserRouter>
<LoggedInProvider>
<MainRoute />
</LoggedInProvider>
</BrowserRouter>
</>
);
}
export default App;
总结
通过以上的描述,即使重新加载浏览器,也能够正确地保持登录状态。
*当然,如果注销并且丢弃cookie,就会被注销。
登录时,注册信息已经散落在互联网上,
但是在重新加载后如何保留这些信息,
我发现很少有明确说明的文章,
所以这对我的学习很有帮助!