【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逐页重新获取)

01.png
02.png

终于解决了问题。

以上的方法允许在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,就会被注销。

登录时,注册信息已经散落在互联网上,
但是在重新加载后如何保留这些信息,
我发现很少有明确说明的文章,
所以这对我的学习很有帮助!

广告
将在 10 秒后关闭
bannerAds