React纯前端模拟实现登录鉴权
作者:慕仲卿
一、目标
本文档旨在阐述前端模拟登录鉴权的实现机制,该机制通过前端技术和 LocalStorage
实现用户的登录状态管理,以确保用户未登录时无法直接访问系统的内层页面,并通过定时器更新登录状态,以保持用户的活动会话。
二、鉴权规则设计
2.1 登录状态判断
系统通过检查 LocalStorage
中的 isLogin
字段来判断用户是否已登录。若 LocalStorage
中不存在 isLogin
字段,则视为用户未登录。
2.2 未登录重定向
若用户未登录,且尝试直接访问以下受保护的页面:'/FactoryView', '/FactoryView/ServerNumView', '/FactoryView/ServerNumView/DeviceView', '/GlobalView', '/AdminAreaView'
,系统将会自动将用户重定向至 '/Login'
页面。
2.3 登录状态设置
用户成功登录后,系统会在 LocalStorage
中设置 isLogin
字段,其值为当前的时间戳(以毫秒为单位)。
2.4 定时更新登录状态
用户一旦进入受保护的内层页面,页面会启动一个定时器,该定时器每 5 秒钟更新 LocalStorage
中的 isLogin
字段,将其值设置为当前时间戳。这确保了只要用户保持在内层页面,其登录状态就会持续更新。
2.5 会话超时处理
若用户关闭了 App
页面或离开了受保护的内层页面,定时器将停止工作,isLogin
字段的值将不再更新。当用户再次尝试访问受保护页面时,系统会检查 isLogin
中的时间戳与当前时间的差异。若差异超过 30 分钟,则视为会话超时,用户将被重定向至登录页面。反之,若时间差在 30 分钟以内,则允许用户访问内层页面,并重启定时器更新 isLogin
字段。
2.6 流程图
上述规则可以使用下面的流程图表示为:
三、Hook代码实现
为实现上述鉴权逻辑,我们创建了一个自定义 Hook :useIntervalWhenStarted
。这个 Hook 用于在组件挂载时启动一个定时器,该定时器每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使用方式
在需要实现登录鉴权的内层页面中,引入并使用该 Hook:
import { useIntervalWhenStarted } from "@/hooks"; // ... 页面组件代码 ... useIntervalWhenStarted(); // ... 页面组件其余代码 ...
四、在最外层对路由进行拦截
下面就以 UMI.js 框架为例,说明如何拦截路由。
根据 UMI.js 的结构特性,所有组件的渲染必定经过预设的 layout
,因此在 layouts/index.tsx
的组件渲染之前对路由进行检测,根据其是否否和要求进行拦截:
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
就是用来检测用户是否具有查看内层页面权限的,其实现为:
/** * 检查登录状态,如果没有登录则强制到登录页 */ 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', }) } } }
五、亮点说明
亮点一:无服务器端的会话管理
传统的会话管理通常需要服务器端的支持,通过服务器来记录用户的登录状态和会话信息。然而,在本鉴权机制中,我们采用了前端技术和 LocalStorage
来实现会话管理,无需依赖服务器端。这降低了服务器的负载,并提高了应用的响应速度。
亮点二:自动会话续期
通过在内层页面设置定时器,每 5 秒钟自动更新 LocalStorage
中的 isLogin
字段,实现了会话的自动续期。这种方法能够确保用户在保持页面活跃的情况下,其会话始终有效,避免了用户频繁登录的烦恼。
亮点三:灵活的会话超时处理
本机制通过比较 isLogin
字段中的时间戳与当前时间的差异,来判断会话是否超时。这种方法既灵活又高效,允许系统在用户离开页面后的一段时间内保持会话有效,同时又能及时识别和处理超时情况,提升了用户体验和系统安全性。
亮点四:模块化、可复用的Hook实现
通过创建一个自定义的 Hook(useIntervalWhenStarted
),我们将鉴权逻辑封装成了一个独立的、可复用的模块。这使得该逻辑可以轻松地集成到任何需要鉴权的 React 组件中,提高了代码的复用性和可维护性。
六、总结
通过上述设计,我们实现了一个前端模拟的登录鉴权机制。该机制通过 LocalStorage
和定时器来管理用户的登录状态,确保了未登录用户无法直接访问受保护的内层页面,并通过定时器持续更新登录状态以防止会话超时。
到此这篇关于React纯前端模拟实现登录鉴权的文章就介绍到这了,更多相关React登录鉴权内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!