样式修改
在登陆页添加微信登陆
<Form.Item>其他登陆方式:<Button onClick={handleWeixinLogin}>微信</Button></Form.Item>
扫码页面
// 使用微信扫码登陆const handleWeixinLogin = async() => {const origin: string = window.location.origin;window.location.href= `http://gmall-h5-api.atguigu.cn/api/user/weixin/login?redirect_uri=${origin}`}
后端会根据redirect_uri,当用户扫码登陆一下,会跳转到login页面,在页面参数中会携带token,
登陆流程处理
最后,在withAuthorization中统一处理登陆逻辑。
import { FC } from "react";import { useLocation, Navigate } from "react-router-dom";import { Spin } from "antd";import { useAppDispatch, useAppSelector } from "@/app/hooks";import { getUserInfoAsync, selectUser, setToken } from "@/pages/login/slice";/*高阶组件HOC本质上是一个函数,接受组件作为参数,返回一个新组件WrappedComponent 组件是哪个?看路由路径(地址)/login --> EmptyLayout/Login/syt/dashboard --> Layout/Dashboard*/function withAuthorization(WrappedComponent: FC) { // FunctionComponentreturn () => {// 读取redux中管理的token和用户名 ==> 只要状态数据发生了改变, 当前组件函数就会自动重新执行const { token, name } = useAppSelector(selectUser);// 获取当前请求的路由地址const { pathname } = useLocation();const dispatch = useAppDispatch();// 如果有token, 说明至少登录过if (token) {...} else { // 没有登录过 => 都得去登陆页面// 判断是否是微信扫码登陆const params = new URLSearchParams(document.location.search.substring(1));const token = params.get('token');if (token) {// 微信扫码登陆,获取到token,直接跳转到首页dispatch(setToken(token))return <Navigate to="/syt/dashboard" />;}// 如果访问的是登陆页面, 直接显示对应的组件if (pathname === "/login") {return <WrappedComponent />;}// // 如果访问不是登录页面, 自动跳转到登陆页面return <Navigate to="/login" />;}};}export default withAuthorization;
在store中定义一个setToken方法,用来保存微信扫码后获取到的token
// 创建当前redux模块的管理对象sliceconst userSlice = createSlice({name: 'user', // 标识名称initialState, // 初始状态// 配置同步action对应的reducer => 同步action会自动生成reducers: {setToken: (state, action) => {// 用来保存微信扫码登陆的tokenconst token = action.payload;state.token = tokenlocalStorage.setItem('token_key', token)}},})export const { setToken } = userSlice.actions;
尚品汇扫码登陆功能实现代码分支:https://github.com/zxfjd3g/gshop-client/tree/feature/wx-login
