指路:从零实现一个React+Antd5.0后台管理系统-系统简介及设计 - 掘金 (juejin.cn)
博主大大只写了登录模块,我想写个注册模块,目前的问题是注册成功后跳转到登录页面,点击登录后提示"用户不存在",想知道如何解决这个问题o(╥﹏╥)o
我的第一反应是没存到数据库的user表里(确实没存到)
然而似乎还有JWT认证相关的问题
我是菜鸡,看了博主大大的登录模块对token相关的逻辑处理,还是不能举一反三到注册模块
下面是我修改的代码(都是AI的)
前端:
1. 新建src/pages/Register/index.jsx, css代码沿用login的,注册部分包括用户名,密码,确认密码,注册按钮和重置按钮
import React, { useState } from 'react'
import { Button, Form, Input, message } from 'antd'
import { useNavigate } from 'react-router-dom'
import { useDispatch } from 'react-redux'
import classes from './Register.module.scss'
import { registerAsync } from '@/store/reducers/userSlice'
const Register = () => {
const dispatch = useDispatch()
const navigate = useNavigate()
const [form] = Form.useForm()
const [loading, setLoading] = useState(false)
const onFinish = async (values) => {
setLoading(true);
try {
// 使用新的注册异步 action
await dispatch(registerAsync(values));
setLoading(false);
message.success('注册成功!');
navigate('/login', { replace: true });
} catch (e) {
console.error(e);
setLoading(false);
message.error('注册失败,请重试!');
}
};
return (
<div className={classes.register}>
<div className={classes['register-container']}>
<div className={classes['register-form']}>
<Form
name="basic"
form={form}
labelCol={{ span: 8 }}
wrapperCol={{ span: 16 }}
onFinish={onFinish}
autoComplete="off">
<Form.Item label="用户名" name="username" rules={[{ required: true, max: 12, message: '请输入用户名!' }]}>
<Input />
</Form.Item>
<Form.Item label="密码" name="password" rules={[{ required: true, message: '请输入密码!' }]}>
<Input.Password />
</Form.Item>
<Form.Item label="确认密码" name="confirmPassword" rules={[{ required: true, message: '请确认密码!' }]}>
<Input.Password />
</Form.Item>
<Form.Item wrapperCol={{ offset: 10, span: 16 }}>
<Button type="primary" htmlType="submit" loading={loading}>
注册
</Button>
<Button htmlType="reset" style={{ marginLeft: '32px' }}>
重置
</Button>
</Form.Item>
</Form>
</div>
</div>
</div>
)
}
export default Register
2. 在src/api/user/index.js中添加用户注册请求
//添加用户注册请求
function registerUser(form) {
return request({
url: '/user/register',
method: 'post',
data: form
})
}
3. 在src/router/index.js中添加了:
导入懒依赖: const Home = lazy(() => import('@/pages/Home'))
添加path: { path: 'register', title: '注册', element: <Register /> }
4. src/store/reducer/userSlice.js下有登录异步方法,我如何照猫画虎实现注册异步方法?
4.1. 定义注册相关的 Action Creators
在reducers中添加:
// 注册开始
registerStart: (state) => {
state.isLoading = true;
},
// 注册成功
registerSuccess: (state, action) => {
state.isLoading = false;
state.token = action.payload.token;
state.userinfo = action.payload.userinfo;
},
// 注册失败
registerFail: (state, action) => {
state.isLoading = false;
state.error = action.payload;
}
4.2. 创建注册的异步 Action Creator
// 注册异步方法
export const registerAsync = (form) => async (dispatch) => {
try {
dispatch(registerStart()); // 分派注册开始 action
const response = await userApi.register.register(form);
dispatch(registerSuccess(response.data)); // 分派注册成功 action
// 注册成功后可能需要导航到其他页面或执行其他操作
} catch (error) {
dispatch(registerFail(error.message)); // 分派注册失败 action
}
};
4.3. 更新 Register 组件以使用新的注册 Action
更新 src/pages/Register/index.jsx 组件,使用 useDispatch 钩子分派新的 registerAsync action
// src/pages/Register/index.jsx
const Register = () => {
// ...组件其他代码
const onFinish = async (values) => {
setLoading(true);
try {
// 使用新的注册异步 action
await dispatch(registerAsync(values));
setLoading(false);
message.success('注册成功!');
navigate('/login', { replace: true });
} catch (e) {
console.error(e);
setLoading(false);
message.error('注册失败,请重试!');
}
};
// ...组件的其余部分
};
export default Register;
5. App.jsx如何实现注册的逻辑
启动项目先进入注册页面,注册成功后跳转到登录页面
import React, { Suspense, useEffect } from 'react';
// 导入路由及react-redux钩子
import { useLocation, useNavigate, useRoutes } from 'react-router-dom';
import { useDispatch, useSelector } from 'react-redux';
// 导入api
import { getUserInfoAsync } from './store/reducers/userSlice';
import { generateRoutes } from './store/reducers/permissionSlice';
import { getToken } from './utils/auth';
// 导入loading组件
import Loading from '@/components/Loading';
export default function App() {
// redux hook
const dispatch = useDispatch();
const routes = useSelector((state) => state.permission.routes);
// 跳转方法
const navigate = useNavigate();
const location = useLocation();
useEffect(() => {
const fetchData = async () => {
// 检查是否存在 token,如果存在则获取用户信息并生成路由
// 如果不存在 token 或者用户信息表明需要注册(例如用户是新用户或者尚未注册),则跳转到注册页面
if (getToken()) {
try {
const userInfo = await dispatch(getUserInfoAsync());
dispatch(generateRoutes(userInfo.menus));
} catch (error) {
console.error('获取用户信息失败,跳转到注册页面', error);
navigate('/register', { replace: true });
}
} else {
// 直接跳转到注册页面
navigate('/register', { replace: true,state: { preLocation: location } });
}
};
fetchData();
}, [dispatch, navigate]);
// 利用hook转换路由表
const element = useRoutes(routes);
return (
<>
<Suspense fallback={<Loading />}>{routes && element}</Suspense>
</>
);
}
后端
1. router/user.js中添加注册接口:
//注册
router.post('/register', userHandler.register);
2. 在schema/user.js新增:
//确认密码的验证规则
const confirmPassword = joi.string().pattern(/^[\\S]{6,12}$/).required()
.messages({
'string.empty': '确认密码必填',
'any.required': '确认密码必填',
'string.pattern.base': '确认密码必须与密码相同'
})
//注册表单的验证规则对象
exports.user_register_schema = joi.object().keys({
username,
password,
confirmPassword
})
3. 如何在router_handler/user.js中添加一个注册路由的处理函数?
3.1. 引入注册表单的验证规则对象
3.2. 注册路由处理函数
exports.register = async (req, res, next) => {
try {
// 使用Joi验证请求体数据
const { value, error } = user_register_schema.validate(req.body);
if (error) {
// 如果验证失败,返回错误信息
return res.status(400).json({
code: 1,
message: '参数验证失败',
data: error.details
});
}
// 从验证后的数据中获取用户名和密码
const { username, password, confirmPassword } = value;
// 检查两次密码是否一致
if (password !== confirmPassword) {
return res.status(400).json({
code: 1,
message: '两次输入的密码不一致',
data: null
});
}
// 检查用户名是否已存在
const existingUser = await UsersModel.findOne({ where: { username } });
if (existingUser) {
return res.status(400).json({
code: 1,
message: '用户名已存在',
data: null
});
}
// 加密密码
const hashedPassword = await bcrypt.hash(password, 10);
// 创建新用户对象
const newUser = {
username,
password: hashedPassword
// 可以添加其他字段,如 email、nickname 等
};
// 将新用户数据存储到数据库
const result = await UsersModel.create(newUser);
if (result) {
res.status(200).json({
code: 0,
message: '用户注册成功',
data: result
});
} else {
res.status(500).json({
code: 1,
message: '用户注册失败',
data: null
});
}
} catch (err) {
// 异常处理,记录日志等
console.error(err);
res.status(500).json({
code: 1,
message: '服务器错误',
data: null
});
}
};