React純前端模擬實(shí)現(xiàn)登錄鑒權(quán)
一、目標(biāo)
本文檔旨在闡述前端模擬登錄鑒權(quán)的實(shí)現(xiàn)機(jī)制,該機(jī)制通過前端技術(shù)和 LocalStorage 實(shí)現(xiàn)用戶的登錄狀態(tài)管理,以確保用戶未登錄時(shí)無法直接訪問系統(tǒng)的內(nèi)層頁面,并通過定時(shí)器更新登錄狀態(tài),以保持用戶的活動(dòng)會(huì)話。
二、鑒權(quán)規(guī)則設(shè)計(jì)
2.1 登錄狀態(tài)判斷
系統(tǒng)通過檢查 LocalStorage 中的 isLogin 字段來判斷用戶是否已登錄。若 LocalStorage 中不存在 isLogin 字段,則視為用戶未登錄。
2.2 未登錄重定向
若用戶未登錄,且嘗試直接訪問以下受保護(hù)的頁面:'/FactoryView', '/FactoryView/ServerNumView', '/FactoryView/ServerNumView/DeviceView', '/GlobalView', '/AdminAreaView',系統(tǒng)將會(huì)自動(dòng)將用戶重定向至 '/Login' 頁面。
2.3 登錄狀態(tài)設(shè)置
用戶成功登錄后,系統(tǒng)會(huì)在 LocalStorage 中設(shè)置 isLogin 字段,其值為當(dāng)前的時(shí)間戳(以毫秒為單位)。
2.4 定時(shí)更新登錄狀態(tài)
用戶一旦進(jìn)入受保護(hù)的內(nèi)層頁面,頁面會(huì)啟動(dòng)一個(gè)定時(shí)器,該定時(shí)器每 5 秒鐘更新 LocalStorage 中的 isLogin 字段,將其值設(shè)置為當(dāng)前時(shí)間戳。這確保了只要用戶保持在內(nèi)層頁面,其登錄狀態(tài)就會(huì)持續(xù)更新。
2.5 會(huì)話超時(shí)處理
若用戶關(guān)閉了 App 頁面或離開了受保護(hù)的內(nèi)層頁面,定時(shí)器將停止工作,isLogin 字段的值將不再更新。當(dāng)用戶再次嘗試訪問受保護(hù)頁面時(shí),系統(tǒng)會(huì)檢查 isLogin 中的時(shí)間戳與當(dāng)前時(shí)間的差異。若差異超過 30 分鐘,則視為會(huì)話超時(shí),用戶將被重定向至登錄頁面。反之,若時(shí)間差在 30 分鐘以內(nèi),則允許用戶訪問內(nèi)層頁面,并重啟定時(shí)器更新 isLogin 字段。
2.6 流程圖
上述規(guī)則可以使用下面的流程圖表示為:



三、Hook代碼實(shí)現(xiàn)
為實(shí)現(xiàn)上述鑒權(quán)邏輯,我們創(chuàng)建了一個(gè)自定義 Hook :useIntervalWhenStarted。這個(gè) Hook 用于在組件掛載時(shí)啟動(dòng)一個(gè)定時(shí)器,該定時(shí)器每5秒更新 LocalStorage 中的 isLogin 字段。
3.1 Hook代碼
import { useState, useEffect } from 'react';
const useIntervalWhenStarted = () => {
useEffect(() => {
let timer = null;
timer = setInterval(() => {
window.localStorage.setItem('isLogin', (+new Date()).toString());
}, 5 * 1000);
return () => {
if (timer) {
clearInterval(timer);
}
};
}, []);
return [];
};
export { useIntervalWhenStarted };
3.2 Hook使用方式
在需要實(shí)現(xiàn)登錄鑒權(quán)的內(nèi)層頁面中,引入并使用該 Hook:
import { useIntervalWhenStarted } from "@/hooks";
// ... 頁面組件代碼 ...
useIntervalWhenStarted();
// ... 頁面組件其余代碼 ...
四、在最外層對(duì)路由進(jìn)行攔截
下面就以 UMI.js 框架為例,說明如何攔截路由。
根據(jù) UMI.js 的結(jié)構(gòu)特性,所有組件的渲染必定經(jīng)過預(yù)設(shè)的 layout,因此在 layouts/index.tsx 的組件渲染之前對(duì)路由進(jìn)行檢測(cè),根據(jù)其是否否和要求進(jìn)行攔截:
import React from 'react';
import store from 'store';
import { ConfigProvider } from 'antd';
import { Outlet } from '@umijs/max';
import { checkIfLogin } from "@/utils/utils";
import Intl from 'react-intl-universal';
import intlzhCN from '@/locales/zh-CN';
import intlenUS from '@/locales/en-US';
import "./index.less";
const locale = {
'zh-CN': require('antd/lib/locale/zh_CN'),
'en-US': require('antd/lib/locale/en_US'),
};
const BasicLayout: React.FC<any> = (props) => {
const { children } = props;
console.log(props);
const lang = store.get('umi_locale') || 'zh-CN';
Intl.init({
currentLocale: lang,
locales: {
'zh-CN': intlzhCN,
'en-US': intlenUS,
},
});
checkIfLogin();
return (
<ConfigProvider componentSize="small" locale={locale[lang].default}>
{children}
<Outlet />
</ConfigProvider>
);
};
export default BasicLayout;上面的代碼中 checkIfLogin 就是用來檢測(cè)用戶是否具有查看內(nèi)層頁面權(quán)限的,其實(shí)現(xiàn)為:
/**
* 檢查登錄狀態(tài),如果沒有登錄則強(qiáng)制到登錄頁
*/
export const checkIfLogin = () => {
const gap = 30 * 60 * 1000;
const login = window.localStorage.getItem('isLogin');
const location = useLocation();
const { pathname } = location;
if(['/Login','/login'].includes(pathname)) return;
if(!login) {
history.push({
pathname: '/Login',
})
} else {
const timeStamp = parseInt(login);
const current = +new Date();
if (current-timeStamp>gap) {
window.localStorage.removeItem('isLogin');
history.push({
pathname: '/Login',
})
}
}
}
五、亮點(diǎn)說明
亮點(diǎn)一:無服務(wù)器端的會(huì)話管理
傳統(tǒng)的會(huì)話管理通常需要服務(wù)器端的支持,通過服務(wù)器來記錄用戶的登錄狀態(tài)和會(huì)話信息。然而,在本鑒權(quán)機(jī)制中,我們采用了前端技術(shù)和 LocalStorage 來實(shí)現(xiàn)會(huì)話管理,無需依賴服務(wù)器端。這降低了服務(wù)器的負(fù)載,并提高了應(yīng)用的響應(yīng)速度。
亮點(diǎn)二:自動(dòng)會(huì)話續(xù)期
通過在內(nèi)層頁面設(shè)置定時(shí)器,每 5 秒鐘自動(dòng)更新 LocalStorage 中的 isLogin 字段,實(shí)現(xiàn)了會(huì)話的自動(dòng)續(xù)期。這種方法能夠確保用戶在保持頁面活躍的情況下,其會(huì)話始終有效,避免了用戶頻繁登錄的煩惱。
亮點(diǎn)三:靈活的會(huì)話超時(shí)處理
本機(jī)制通過比較 isLogin 字段中的時(shí)間戳與當(dāng)前時(shí)間的差異,來判斷會(huì)話是否超時(shí)。這種方法既靈活又高效,允許系統(tǒng)在用戶離開頁面后的一段時(shí)間內(nèi)保持會(huì)話有效,同時(shí)又能及時(shí)識(shí)別和處理超時(shí)情況,提升了用戶體驗(yàn)和系統(tǒng)安全性。
亮點(diǎn)四:模塊化、可復(fù)用的Hook實(shí)現(xiàn)
通過創(chuàng)建一個(gè)自定義的 Hook(useIntervalWhenStarted),我們將鑒權(quán)邏輯封裝成了一個(gè)獨(dú)立的、可復(fù)用的模塊。這使得該邏輯可以輕松地集成到任何需要鑒權(quán)的 React 組件中,提高了代碼的復(fù)用性和可維護(hù)性。
六、總結(jié)
通過上述設(shè)計(jì),我們實(shí)現(xiàn)了一個(gè)前端模擬的登錄鑒權(quán)機(jī)制。該機(jī)制通過 LocalStorage 和定時(shí)器來管理用戶的登錄狀態(tài),確保了未登錄用戶無法直接訪問受保護(hù)的內(nèi)層頁面,并通過定時(shí)器持續(xù)更新登錄狀態(tài)以防止會(huì)話超時(shí)。
到此這篇關(guān)于React純前端模擬實(shí)現(xiàn)登錄鑒權(quán)的文章就介紹到這了,更多相關(guān)React登錄鑒權(quán)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
基于React實(shí)現(xiàn)一個(gè)todo打勾效果
這篇文章主要為大家詳細(xì)介紹了如何基于React實(shí)現(xiàn)一個(gè)todo打勾效果,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-03-03
React?useEffect異步操作常見問題小結(jié)
本文主要介紹了React?useEffect異步操作常見問題小結(jié),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-06-06
React?Context源碼實(shí)現(xiàn)原理詳解
這篇文章主要為大家介紹了React?Context源碼實(shí)現(xiàn)原理示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-10-10
React啟動(dòng)時(shí)webpack版本沖突報(bào)錯(cuò)的解決辦法
在啟動(dòng)React應(yīng)用時(shí),遇到Webpack版本不匹配導(dǎo)致的運(yùn)行錯(cuò)誤,解決方法包括刪除全局及局部的webpack和webpack-cli,然后根據(jù)項(xiàng)目需求安裝特定版本的webpack,本文通過代碼示例給大家介紹的非常詳細(xì),需要的朋友可以參考下2024-09-09
React中使用echarts-for-react的方法示例
echarts-for-react則是ECharts在React生態(tài)中的官方封裝組件,它讓開發(fā)者能夠輕松地在React應(yīng)用中集成ECharts圖表,本文就來介紹一下echarts-for-react的使用,感興趣的可以了解一下2025-03-03

