react+redux完成登录页面及token的存取和登录保持

react+redux完成登录页面及token的存取和路由守卫

关于登录页面,我在写vue项目的时候,写了很多篇博客来记录。原因是登录确实比较复杂,涉及前后端联调、全局数据管理、浏览器本地存储等多个环节的技术。框架换成react后,逻辑是一样的,但是技术栈及语法却完全不一样了,有必要记录一下整个过程。

首先看看登录界面,简单的两个输入框,和一个登录按钮,用的antDesign的UI框架

image-20240327093023168

然后梳理一下流程:

  1. 首先在项目中基于redux设置一个全局数据,也就是token,token是后端返回的带有用户信息的一串字符,不再赘述token的作用,反正就是和用户相关的所有页面都需要用到它
  2. redux中编写保存token的同步方法,以及获取token的异步方法,因为token是通过接口向后端请求的,所以要使用异步方法
  3. 页面提交登录数据,点击提交时发送异步请求,获取token
  4. token持久化存储

一、全局数据管理

首先要安装react-redux

store中新建user.jsx(我用的vite创建项目,最好将js文件都改成jsx,这样不易报错),编写如下代码:

import { createSlice } from "@reduxjs/toolkit";
import http from '../../utils/http'const userStore = createSlice({name: "user",initialState: {token: localStorage.getItem('token_key') || "",},reducers: {setToken(state, action) {state.token = action.payload;localStorage.setItem('token_key', action.payload)},},
});const { setToken } = userStore.actions;const userReducer = userStore.reducer;// 异步方法,登录获取token
const fetchToken = (loginForm) => {return async (dispatch) => {const res = await http.post('/authorizations', loginForm)// const res = await http.post('/user/login', loginForm)// 提交同步action进行token保存dispatch(setToken(res.data.token))}
}export { setToken, fetchToken };export default userReducer;

同步方法写在reducer中,即setToken方法,用于将全局token修改为获取到的token,在获取token后,同时在localstorage中设置token_key

异步方法就是fetchToken,实际上就是搜集用户填写的登录信息,并基于此信息向后端发起异步请求,然后调用dispatch提交同步action执行setToken函数

有个需要主意的,token的初始化localStorage.getItem('token_key') || "",,其实在vue中也是这么用的

二、页面登录时执行异步方法

先上代码

import "./index.scss";
import { Card, Form, Input, Button, message } from "antd";
import logo from "../../assets/logo.png";
import { useState } from "react";
import { fetchToken } from "../../store/modules/user";
import { useDispatch } from "react-redux";
import { useNavigate } from "react-router-dom";const Login = () => {const dispatch = useDispatch();const navigate = useNavigate();const onFinish = async (values) => {console.log(values);await dispatch(fetchToken(values))navigate('/')message.success('登录成功')};return (<div className="login"><Card className="login-container"><img className="login-logo" src={logo} alt="" />{/* 登录表单 */}<Form validateTrigger={["onBlur"]} onFinish={onFinish}><Form.Itemname="mobile"rules={[{required: true,message: "请输入手机号!",},{pattern: /^1[3-9]\d{9}$/,message: "手机号码格式不对",},]}><Input size="large" placeholder="请输入手机号" /></Form.Item><Form.Itemname="code"rules={[{required: true,message: "请输入验证码!",},]}><Input size="large" placeholder="请输入验证码" maxLength={6} /></Form.Item><Form.Item><Button type="primary" htmlType="submit" size="large" block>登录</Button></Form.Item></Form></Card></div>);
};export default Login;

核心就是上面的onfinish回调方法

  const onFinish = async (values) => {await dispatch(fetchToken(values))navigate('/')message.success('登录成功')};

首先,values就是用户填写的登录信息{mobile: ‘xxxxxx’, code: ‘246810’}

然后,执行redux中的异步方法,获取token,并存储token

最后,路由跳转,并通知用户登录成功

三、请求拦截器中注入token

向后端发送请求,为了保证数据安全,一般都需要携带token,vue写了很多相关的博客了,原理一样,为保证内容的连贯性,我放上相关的代码

在封装的axios函数中,编写以下代码

import axios from "axios";
import { getToken } from "./token";const http = axios.create({baseURL: "http://geek.itheima.net/v1_0",timeout: 5000,
});// axios请求拦截器
http.interceptors.request.use((config) => {const token = getToken()if (token) {config.headers.Authorization = "Bearer " + token;}return config;},(e) => Promise.reject(e)
);// axios响应式拦截器
http.interceptors.response.use((res) => res.data,(e) => {console.log(e);return Promise.reject(e);}
);export default http;

其中,getToken是封装的从localstorage中取token的方法,代码如下:

const TOKENKEY = "token_key";function setToken(token) {return localStorage.setItem(TOKENKEY, token);
}function getToken() {return localStorage.getItem(TOKENKEY);
}function clearToken() {return localStorage.removeItem(TOKENKEY);
}export { setToken, getToken, clearToken };

四、路由鉴权/路由守卫

在vue中,叫路由守卫,写在router/index.js中,只有用户登录成功后,也就是说有了token后,才能访问其他页面,vue中的路由守卫我也写了很多相关的博客了,可以参考,react中的做法要比vue中麻烦多了

实现步骤

  1. 在 components 目录中,创建 AuthRoute/index.jsx 文件
  2. 登录时,直接渲染相应页面组件
  3. 未登录时,重定向到登录页面
  4. 将需要鉴权的页面路由配置,替换为 AuthRoute 组件渲染

components/AuthRoute/index.jsx代码

import { getToken } from '../../utils/token'
import { Navigate } from 'react-router-dom'const AuthRoute = ({ children }) => {const isToken = getToken()if (isToken) {return <>{children}</>} else {return <Navigate to="/login" replace />}
}export default AuthRoute

然后修改路由

src/router/index.jsx代码

import { createBrowserRouter } from 'react-router-dom'import Login from '@/pages/Login'
import Layout from '@/pages/Layout'
import AuthRoute from '@/components/Auth'const router = createBrowserRouter([{path: '/',element: <AuthRoute><Layout /></AuthRoute>,},{path: '/login',element: <Login />,},
])export default router

而vue中,只需要是router/index.js中编写路由守卫相关的代码就行了,我的一般写法如下:

// 路由守卫
import jwt_decode from "jwt-decode";
router.beforeEach((to, from, next) => {const isLogin = localStorage.user ? true : false;if (isLogin) {const user = JSON.parse(localStorage.user)const decode = jwt_decode(user.userInfo.token);const date = parseInt(new Date().getTime() / 1000);if (date - decode.iat > decode.exp - decode.iat) {localStorage.removeItem("user");next("/login");}}if (to.path == "/login") {next();} else {isLogin ? next() : next("/login");}
});export default router;

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

虹科Pico汽车示波器 | 免拆诊断案例 | 2018款东风风神AX7车发动机怠速抖动、加速无力

一、故障现象 一辆2018款东风风神AX7车&#xff0c;搭载10UF01发动机&#xff0c;累计行驶里程约为5.3万km。该车因发动机怠速抖动、加速无力及发动机故障灯异常点亮而进厂维修&#xff0c;维修人员用故障检测仪检测&#xff0c;提示气缸3失火&#xff1b;与其他气缸对调点火线…

【Flink架构】关于FLink BLOB的组织架构:FLIP-19: Improved BLOB storage architecture:官网解读

文章目录 一. BlobServer架构1.BlobClient2. BlobServer3. BlobCache4. LibraryCacheManager 二、BLOB的生命周期1. 分阶段清理2. BlobCache的生命周期3. BlobServer 三、文件上下载流程1. BlobCache 下载2. BlobServer 上传3. BlobServer 下载 四. Flink中支持的BLOB文件类型1…

electron打包桌面版.exe之vue项目踩坑(vue3+electron 解决打包后首页打开空白,打包后路由不跳转及请求不到后端数据等问题)

vue项目https://www.qingplus.cn/components-web/index打包桌面版问题集合 一、静态资源加载问题 npm run electron_dev桌面版运行后页面空白&#xff0c;内容未加载。 填坑&#xff1a; 打包配置要用相对路径 vite.config.ts文件中的base要改成./&#xff0c;之前加了项目…

AWS基础网络产品及协同架构-Networking

简介 一个完整的AWS网络架构图&#xff0c;包含了如下能力&#xff1a; Users (用户): 表示使用AWS服务的用户或系统。 SaaS (软件即服务): 表示在AWS上运行的软件服务&#xff0c;如企业微信可能作为SaaS提供。 example.com?: 这可能是一个示例域名&#xff0c;用于展示如何…

ES面试题

1、如何同步索引库 同步调用 在完成数据库操作后&#xff0c;直接调用搜索服务提供的接口 异步通知 在完成数据库操作后&#xff0c;发送MQ消息 搜索服务监听MQ&#xff0c;接收到消息后完成数据修改 监听binlog 2、分词器 ik分词器 ik_smart ik_max_word 自定义分词器 以拼…

Zookeeper的系统架构

先看一张图&#xff1a; ZooKeeper 的架构图中我们需要了解和掌握的主要有&#xff1a; 1&#xff1a; ZooKeeper分为服务器端&#xff08;Server&#xff09; 和客户端&#xff08;Client&#xff09;&#xff0c;客户端可以连接到整个ZooKeeper服务的任意服务器上&#xff…

ADC+DMA

接线图 这个部分的数据转运是在STM32内部进行的&#xff0c;无需其他外加模块&#xff0c;首先印证一下定义的数据是否储存在相应的地址区间里。

华为CLI实验-配置旁路检测时的安全策略

CLI举例&#xff1a;配置旁路检测时的安全策略 举例说明当FW作为旁路检测设备时&#xff0c;如何配置安全策略。 组网需求 如图1所示&#xff0c;企业内网通过路由器Router连接到Internet。FW作为旁路检测设备&#xff0c;对通过Router的流量进行内容安全检测。 图1 旁路检测…

UniRepLKNet:一种用于音频、视频、点云、时间序列和图像识别的通用感知大核卷积神经网络

论文: https://arxiv.org/abs/2311.15599 模型: https://huggingface.co/DingXiaoH/UniRepLKNet/tree/main 主页&#xff1a;https://invictus717.github.io/UniRepLKNet/ contribution 提出了四条guide line用于设计大核CNN架构模型&#xff0c;用于图像识别&#xff0c;语…

视图的作用

目录 视图的作用 创建视图 为 scott 分配创建视图的权限 查询视图 复杂视图的创建 视图更新的限制问题 更新视图中数据的部门编号&#xff08;视图的存在条件&#xff09; 限制通过视图修改数据表内容 创建只读的视图 复杂视图创建 oracle从入门到总裁:​​​​​​h…

数据结构——线性表(一)

线性表&#xff0c;顾名思义&#xff0c;是具有像线一样的性质的表。如同学生们在操场上排队&#xff0c;一个跟着一个排队&#xff0c;有一个打头&#xff0c;有一个收尾&#xff0c;在其中的学生都知道前一个是谁&#xff0c;后一个是谁&#xff0c;这样就像一根线将他们都串…

协程库-锁类-实现线程互斥同步

mutex.h&#xff1a;信号量&#xff0c;互斥锁&#xff0c;读写锁&#xff0c;范围锁模板&#xff0c;自旋锁&#xff0c;原子锁 锁 **锁不能进行拷贝操作&#xff1a;**锁是用于管理多线程并发访问共享资源的同步原语。这些锁包括互斥锁&#xff08;mutex&#xff09;、读写锁…