React封装登录逻辑

news2024/9/25 7:24:42

在写React项目的时候在登录这块对于用户身份失效自动跳到登录页这块让我头大,问题在于:知道请求为401的时候才会跳到登录页让用户身份认证,因为不可能在每个请求都要判断一下是否为401于是我们就会在封装axios的地方单独判断是否为401,此时问题就出来了如何在请求判断为401时通知组件更新,于是我就通过redux来通知因为我们知道redux既可以在组件中使用也可以在js文件中使用,废话不多说下面就是我的代码,点击我查看完整代码

第一步

判断是否请求为401,当请求为401时移除已存在的token并且使用redux的action更新store

http.request.js

import axios from "axios";
import {store} from "@/redux/store.js";
import {authorizeAction} from "@/redux/feature/authorize.js";
import {getToken, getTokenName, removeToken} from "@/lib/toolkit/local.storage.js";

const URL = import.meta.env.VITE_REACT_APP_PATH

// 创建 axios 请求实例
const serviceAxios = axios.create({
	baseURL:URL, // 基础请求地址
	timeout: 10000, // 请求超时设置
	withCredentials: false, // 跨域请求是否需要携带 cookie
});

// 创建请求拦截
serviceAxios.interceptors.request.use(
	(config) => {
		config.headers = {'Content-Type': 'application/json',...config.headers,[getTokenName()]:getToken()};
		return config;
	},
	(error) => {
		return Promise.reject(error);
	}
);


// 创建响应拦截
serviceAxios.interceptors.response.use(
	(res) => {
		if (res.data.code === 401) {
			//移除之前的token
			removeToken()
			store.dispatch(authorizeAction())
		}
		return res.data;
	},
	(error) => {
		let msg = "网络异常问题,请联系管理员!";
		if (error && error.response) {
			switch (error.response.status) {
				case 302:
					msg = "接口重定向了!";
					break;
				case 400:
					msg = "参数不正确!";
					break;
				case 401:
					msg = "您未登录,或者登录已经超时,请先登录!";
					break;
				case 403:
					msg = "您没有权限操作!";
					break;
				case 404:
					msg = `请求地址出错: ${error.response.config.url}`;
					break;
				case 408:
					msg = "请求超时!";
					break;
				case 409:
					msg = "系统已存在相同数据!";
					break;
				case 500:
					msg = "服务器内部错误!";
					break;
				case 501:
					msg = "服务未实现!";
					break;
				case 502:
					msg = "网关错误!";
					break;
				case 503:
					msg = "服务不可用!";
					break;
				case 504:
					msg = "服务暂时无法访问,请稍后再试!";
					break;
				case 505:
					msg = "HTTP 版本不受支持!";
					break;
				default:
					msg = "异常问题,请联系管理员!";
					break;
			}
		}
		return Promise.reject(msg);
	}
);

const request = {
	post:(url,data = {}) => {
		return serviceAxios({
			url: url,
			method: "post",
			data: data,
			headers: {
				"Content-Type": "application/json"
			}
		})
	},
	get:(url,params = {})=>{
		return serviceAxios({
			url: url,
			method: "get",
			params: params,
			headers: {
				"Content-Type": "application/json"
			}
		})
	}
}



export {URL}

export default request;

store.js: devTools用于浏览器插件,middleware:这是一个配置选项,默认情况下,Redux Toolkit 会检查每个动作和状态是否可序列化(即能被 JSON.stringify 处理),以确保 Redux 状态树的一致性和可预测性。在某些情况下(如使用某些类型的非序列化数据),可能需要关闭此检查

import {configureStore} from "@reduxjs/toolkit";
import {composeWithDevTools} from "@redux-devtools/extension";
import {authorizeReducer} from "@/redux/feature/authorize.js";

//存储状态
export const store = configureStore({
	reducer:{
		authorize:authorizeReducer
	},
	devTools:composeWithDevTools(),
	middleware : (getDefaultMiddleware) => {
		return getDefaultMiddleware({
			serializableCheck: false
		})
	}
});

authorize.js

import {isBlank} from "@/lib/toolkit/util.js";
import {generateSlice} from "@/lib/toolkit/redux.util.js";
import {getToken} from "@/lib/toolkit/local.storage.js";

const AUTHORIZE_SUCCESS = true;
const AUTHORIZE_FAIL = false;

/**
 *  用于监控TOKEN失效的state
 *  false 授权异常 true 授权正常
 *  TODO BUG 当用户是登录状态退出浏览器在登录会先跳转到首页再跳转到主页
 */
const authorizeProcessor = generateSlice(getRandomId(), AUTHORIZE_FAIL, {
    authorizeAction() {
        return isBlank(getToken()) ? AUTHORIZE_FAIL : AUTHORIZE_SUCCESS
    },
});
const authorizeProcessor = createSlice({
		name:'login',
		initialState:AUTHORIZE_FAIL,
		reducers:{
            authorizeAction: ()=>{
                return isBlank(getToken()) ? AUTHORIZE_FAIL : AUTHORIZE_SUCCESS
            }
        }
	})

export const authorizeReducer = authorizeProcessor.reducer
export const {authorizeAction} = authorizeProcessor.actions
export {AUTHORIZE_FAIL,AUTHORIZE_SUCCESS}

第二步

通知组件更新:封装HOOK放在顶层组件中,

main.jsx

import '@/index.css'
import 'virtual:uno.css'
import ReactDOM from 'react-dom/client';
import {RouterProvider} from "react-router-dom";
import {Suspense} from "react";
import {Loading} from "antd-mobile";
import {Provider} from "react-redux";
import router from "@/router/index.jsx";
import {store} from "@/redux/store.js";

//渲染
ReactDOM.createRoot(document.getElementById('root')).render(
    <Suspense fallback={<Loading/>} >
        <Provider store={store}>
            <RouterProvider router={router}/>
        </Provider>
    </Suspense>
)

App.jsx

import {useEffect} from "react";
import {Outlet, useNavigate} from "react-router-dom";
import {AUTH_PATH, HOME_PATH} from "@/router/index.jsx";
import {useToken} from "@/hook/useToken.jsx";


export default function App() {
    const navigate = useNavigate();
    const {isLogin} = useToken();

    useEffect(() => {
        if (isLogin) {
            navigate(HOME_PATH)
            return
        }
        navigate(AUTH_PATH)
    },[isLogin])
    return (
        <div className='w-full h-full'>
            <Outlet/>
        </div>
    )
}

useToken.jsx:当redux更新了此hook就会被触发并且其中的isLogin会重新计算相当于响应式数据,至于为什么要增加!isBlank(getToken()),就在于每次关闭重新打开我们的网站redux都会初始化,导致用户可能是有token也会被重定向到登录页,所以判断的时候还需要加上token是否存在

import {useDispatch, useSelector} from "react-redux";
import {getToken, removeToken, setToken} from "@/lib/toolkit/local.storage.js";
import {isBlank} from "@/lib/toolkit/util.js";
import {authorizeAction} from "@/redux/feature/authorize.js";

export const useToken = () => {
    const authorize = useSelector(state => state.authorize);
    const dispatch = useDispatch();

    return {
        isLogin: authorize || !isBlank(getToken()),
        token: getToken(),
        logout: () => {
            removeToken();
            dispatch(authorizeAction())
        },
        login: (token) => {
            setToken(token)
            dispatch(authorizeAction())
        }
    }
}

以上的代码就解决开头提出的问题,但是其中有很多工具类啥的代码不完整,点击我查看完整代码

工具类

**local.storage.js:isBlank为工具类的一个方法,其中的const TOKEN_NAME = import.meta.env.VITE_REACT_APP_TOKEN_NAME**语法是来自于dotenv-cli这个依赖包的可以百度自行查看用法,在这里就是获取token存在浏览器的KEY

import {isBlank} from "@/lib/toolkit/util.js";

const TOKEN_NAME = import.meta.env.VITE_REACT_APP_TOKEN_NAME

const getTokenName = () => {
    if (isBlank(TOKEN_NAME)) {
        throw new Error('TOKEN_NAME is null or undefined')
    }
    return TOKEN_NAME
}

const getToken = () => {
    return localStorage.getItem(getTokenName()) || ''
}

const setToken = (token) => {
    localStorage.setItem(getTokenName(), token)
}

const removeToken = () => {
    localStorage.removeItem(getTokenName())
}

const get = (key) => {
    return localStorage.getItem(key);
}

const set = (key,value) => {
    localStorage.setItem(key,value)
}

const remove = (key) => {
    localStorage.removeItem(key)
}

export {getTokenName, getToken, setToken, removeToken, get, set, remove}

因为这只是我自己想的如果有更好的解决方法,愿意请教。谢谢

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2162906.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

微服务(一)

目录 一、概念 1、单体架构 2、微服务 3、springcloud 二、微服务的拆分 1、微服务的拆分原则 1.1 什么时候拆 1.2 怎么拆 2、服务调用 2.1 resttemplate 2.2 远程调用 一、概念 1、单体架构 单体架构&#xff08;monolithic structure&#xff09;&#xff1a;顾名…

项目启动卡住不动Property ‘mapperLocations‘ was not specified.

问题如上图所示&#xff1b; 原因&#xff1a;在mapper打了个断点&#xff01;

js实现多行文本控件textarea,根据文本内容自适应窗口全部显示

概述 本人在使用html控件textarea&#xff0c;多行显示的时候&#xff0c;希望根据后台实际的文本&#xff0c;来全部显示文本内容&#xff0c;而不用再去操作滚动条查看全部文本。 本功能实现的难点在于&#xff0c;计算当前文本显示有多少行。 软件环境 编辑器&#xff1a…

8.11Zero Crossing Detection (零交叉检测)

基本概念 零交叉检测是一种基于二阶导数的边缘检测方法&#xff0c;它通过查找二阶导数过零点来定位边缘。 注意: OpenCV没有直接提供这种检测方法&#xff0c;但可以通过结合其他函数来实现。 在OpenCV中&#xff0c;基于C的Zero Crossing Detection&#xff08;零交叉检测&…

关于PHP方面需要掌握的一些基础语法

成长路上不孤单&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a; 【14后&#x1f60a;///C爱好者&#x1f60a;///持续分享所学&#x1f60a;///如有需要欢迎收藏转发///&#x1f60a;】 今日分享关于【PHP的基础语法】相关内容&#xff01;…

Unity开发绘画板——03.简单的实现绘制功能

从本篇文章开始&#xff0c;将带着大家一起写代码&#xff0c;我不会直接贴出成品代码&#xff0c;而是会把写代码的历程以及遇到的问题、如何解决这些问题都记录在文章里面&#xff0c;当然&#xff0c;同一个问题的解决方案可能会有很多&#xff0c;甚至有更好更高效的方式是…

零售业的数字化转型与消费者体验升级

在数字化浪潮的推动下&#xff0c;零售业正经历着前所未有的变革。数字化转型不仅为零售商带来了新的商业模式和运营效率的提升&#xff0c;更重要的是&#xff0c;它极大地提升了消费者的购物体验。金智维将探讨零售业如何通过数字化转型&#xff0c;实现线上线下融合、智能推…

【架构】NewSQL

文章目录 NewSQLTiDBTiDB 主要组件特点使用场景安装与部署 推荐阅读 NewSQL NewSQL是一种数据库管理系统(DBMS)的类别&#xff0c;它结合了NoSQL数据库的可扩展性和传统SQL数据库的事务一致性。具体来说&#xff0c;NewSQL数据库旨在解决传统关系型数据库在处理大规模并发事务…

通过pyenv local 3.6.1 这里设置了当前目录的python版本,通过pycharm基于这个版本创建一个虚拟环境

要在 PyCharm 中基于你通过 pyenv local 设置的 Python 版本创建虚拟环境&#xff0c;可以按照以下步骤进行操作&#xff1a; 步骤 1: 获取当前使用的 Python 路径 通过 pyenv 查找当前项目下的 Python 解释器路径&#xff0c;使用以下命令&#xff1a; pyenv which python …

Thread , ThreadLocal , ThreadLocalMap , Entry 之间的关系?

Thread , ThreadLocal , ThreadLocalMap , Entry 之间的关系&#xff1f; 首先ThradLocal是线程的本地副本&#xff0c;怎么理解这句话呢&#xff1f;一个Thread都有一个它自己的ThreadLocalMap。ThreadLocalMap不是HashMap的结构&#xff0c;而是一个Entry数组&#xff0c;里面…

报错解决方案

大模型-报错解决方案 百度千帆大模型 仅个人笔记使用&#xff0c;感谢点赞关注 百度千帆大模型 未开通付费模型 qianfan.errors.APIError: api return error, req_id: code: 17, msg: Open api daily request limit reached 可能的原因: 未开通所调用服务的付费权限&#xff0…

【设计模式-观察者模式】

定义 观察者模式&#xff08;Observer Pattern&#xff09;是一种行为型设计模式&#xff0c;用于定义一对多的依赖关系&#xff0c;让多个观察者对象同时监听某一个主题对象&#xff08;被观察者&#xff09;的状态变化。当主题状态发生变化时&#xff0c;所有依赖于它的观察…

00DSP学习-F28379D学习准备(了解一个工程的构成)

叠甲 我也算初学F28379D&#xff0c;不对之处请大家斧正。不同型号的DSP在外设配置的函数上有一些区别&#xff0c;但是掌握一种对其他型号的来说则难度不大。对于我们而言学习DSP最终还是要用于算法验证&#xff0c;而DSP资源的最大化利用、代码效率提升等则是后话。 软件准…

大数据-146 Apache Kudu 安装运行 Dockerfile 模拟集群 启动测试

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; 目前已经更新到了&#xff1a; Hadoop&#xff08;已更完&#xff09;HDFS&#xff08;已更完&#xff09;MapReduce&#xff08;已更完&am…

进阶SpringBoot之分布式系统与 RPC 原理

分布式系统是若干独立计算机的集合&#xff0c;这些计算机对于用户来说就像单个相关系统 分布式系统是由一组通过网络进行通信&#xff0c;为了完成共同的任务而协调工作的计算机节点组成的系统 其目的是利用更多的机器&#xff0c;处理更多的数据 RPC&#xff08;Remote Pr…

【Day20240924】05git 两人协作 冲突

git 两人协作 冲突 命令行解决 两个人修改同一文件时 的冲突可视化解决 两个人修改同一文件时 的冲突参考 命令行解决 两个人修改同一文件时 的冲突 假设kerwin.js是项目的路由文件。tiechui文件夹是组员铁锤的工作目录&#xff1b;test2008文件夹是组长的工作目录。此时&…

JAVA基本简介(期末)

1、JDK JRE JVM &#xff08;1&#xff09;JDK JAVA标准开发包&#xff0c;提供了编译、运行JAVA程序所需的各种工具和资源&#xff0c;包括JAVA编译器、JAVA运行时的环境&#xff0c;及常用的JAVA类库等 &#xff08;2&#xff09;JRE JAVA运行环境&#xff0c;用于解释执行JA…

CNAS软件检测实验室信息安全性测试作业指导书编写指南

CNAS软件检测实验室在申请信息安全领域测试的相关资质时&#xff0c;需要按照GB/T 25000.51-2016《软件产品质量要求和测试细则》标准中的方法&#xff0c;编写作业指导书&#xff0c;指导软件检测实验室内部信息安全性测试的开展。CNAS软件检测实验室信息安全性测试作业指导与…

风力发电机叶片表面缺陷识别检测数据集yolo数据集 共7000张

风力发电机叶片表面缺陷识别检测数据集yolo数据集 共7000张 风力发电机叶片表面缺陷识别数据集&#xff08;Wind Turbine Blade Defects Recognition Dataset, WTBDRD&#xff09; 摘要 WTBDRD 是一个专门为风力发电机叶片表面缺陷识别而设计的数据集&#xff0c;旨在为相关领…

【目标检测】隐翅虫数据集386张VOC+YOLO

隐翅虫数据集&#xff1a;图片来自网页爬虫&#xff0c;删除重复项后整理标注而成 数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;386 标注…