登录功能 | react+antd实现登录页面

实现需求

  • 登录页面展示
  • 实现注册和登录功能
  • 实现登出功能
  • 登录成功实现页面跳转
  • 短时间不需要再登录

实现过程

创建React项目

注意:新版React和之前有较大不同

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import React from 'react';
import { createRoot } from 'react-dom/client';
import App from './App';


// @ts-ignore
const root = createRoot(document.getElementById('root'));
root.render(
<App></App>
);


// 之前的写法是
// ReactDOM.render(<App></App>, document.getElementById('root'))

前端UI登录界面基本布局

这部分我是在pages/login/index.js完成的

当然不要忘记把组件放到App中去~

需求:

  1. 完成登录界面基本布局

  2. 完成登录表单

实现登录界面

采用antd里面的基本布局(header content footer)和表单实现

【不要怕!按照你想的魔改就好了!】

实现效果:

完善注册页面

还是采用antd里面的表单进行实现,这里要注意的是,是点击register now!之后,才会切换到注册页面,这里我觉得注册页面单独没什么必要,所以我采取的是把注册页面嵌套在对话框里面,根据自己的喜好啦~

实现效果:

接口配置

Promise对axios进行二次封装

二次封装的好处在于:

  1. 实现全局axios模块,因为平时发送网络请求多样,有get请求,post请求等等
  2. 可以全局部署请求拦截器和响应拦截器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
// src/api/ajax.js
import axios from 'axios';
import qs from 'qs';
import {message} from 'antd';


const instance = axios.create({
timeout: 10000,
})

// 添加请求拦截器
instance.interceptors.request.use(config => {
// console.log('config', config);
config.headers.Authorization = sessionStorage.getItem('token') || '';
return config;
}, err => {
return Promise.reject(err);
});

// 添加响应拦截器
instance.interceptors.response.use(response => {
console.log(response);
// 我后端是权限校验成功
if (response.data.msg === '权限校验成功!') {
window.history.pushState(null, 'home','/');
} else {
return Promise.reject(response.data.msg);
}
}, err => {
if (err.response) {
// token失效,回到登录页面
window.history.pushState(null, 'login','/login');
}
})

export default function ajax(method='GET', url, data={}, config) {

return new Promise((resolve, reject) => {
let promise;
// 执行异步ajax请求
if (method === 'GET') {
promise = instance({
method:'GET',
url,
params:data,
...config,
}) // params配置指定的是query参数
} else {
promise = axios({
method: 'POST',
url,
data: qs.stringify(data),
headers: {
'Context-type': 'application/json',
'Authorization': 'Bearer ' + window.sessionStorage.getItem('token'),
},
...config,
})
};

promise.then(response => {
// 如果成功了,调用resolve(response.data)
resolve(response);
}).catch(error => { // 对所有ajax请求出错做统一处理,这样外层就不用再处理错误了
// 如果失败了,提示请求后台出错
reject(message.error(error));
})
})
}

写接口

接口主要根据写的后端接口配

解决跨域问题

一开始,我采用CORS解决跨域

报错问题: Refused to set unsafe header “Origin”

这说明设置的Origin字段是无效的,不管我设置什么或者不设置这个字段时查看Origin字段时它的值都是null,有人说那个Origin字段本来就应该是浏览器来设置的,自己设置不安全

所以导致我在服务端写了Access-Control-Allow-Origin一直还是没用,所以后面采用了代理的方式进行跨域

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// src/setupProxy.js
const { createProxyMiddleware } = require('http-proxy-middleware');

module.exports = function (app) {
app.use(
"/api",
createProxyMiddleware({
//api1是需要转发的请求(所有带有/api1前缀的请求都会转发给5000)
target: "http://localhost:5000", //配置转发目标地址(能返回数据的服务器地址)
changeOrigin: true, //控制服务器接收到的请求头中host字段的值
/* changeOrigin设置为true时,服务器收到的请求头中的host为:localhost:5000 changeOrigin设置为false时,服务器收到的请求头中的host为:localhost:3000 changeOrigin默认值为false,但我们一般将changeOrigin值设为true */
pathRewrite: {
"^/api": "" }, //去除请求前缀,保证交给后台服务器的是正常请求地址(必须配置)
})
)
}

最终接口代码:

1
2
3
4
5
6
7
8
9
10
11
// src/api/index.js
import ajax from './ajax';

// 注册
export const reqRegister = (username, password) => ajax('POST', '/api/register', {username, password});

// 登录
export const reqLogin = (username, password) => ajax('POST', '/api/login', {username, password});

// 权限校验
export const reqAuth = () => ajax('POST', '/api/auth', {});

路由部署

实现效果:

  1. 访问home页面,如果没有登录,重定向到login页面
  2. 登录成功后跳转到home页面
  3. home页面设置登出
  4. 设置注册页面,可以提交表单信息

好久没写router了,此时最新的是"react-router-dom": "^6.3.0",发现更新了不少~

不要因为不熟悉就卸载下载旧版本呀【以前的我经常这么干!哈哈哈哈哈】

还是要不断学习!拥抱变化!

(干货) 全网最全 react-router-dom v6.0学习指南

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// src/router/index.js
import Home from '../pages/home';
import Login from '../pages/login';


export const routes = [
{
path: '/',
component: Home,
exact: true,
}, {
path: '/login',
component: Login,
}
];
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// src/App.js
import React from 'react';
import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom';
import { routes } from './router';

export default function App() {
return (
<BrowserRouter>
<Routes>
{
routes.map((route) => (
<Route
key={route.path}
path={route.path}
//exact={route.exact}
element={<route.component/>}
></Route>
))
}
<Route path='*' element={<Navigate to='/login'/>}></Route>
</Routes>
</BrowserRouter>
)
}

这样能够实现路由正常跳转了~

接口调用

接口主要用于实现登录功能,所以基本是下面的流程:

  1. 输入用户名和密码,登录(发送登录请求)
  2. 根据后端返回的结果判断是哪种状态
    1. 登录成功:跳转到主页(’/‘),把返回的token存在sessionStorage里面
    2. 用户不存在:停留在原页面,提示用户不存在
      1. 用户点击register now!之后,弹出注册页面,用户输入信息后,注册(发送注册请求)
    3. 密码错误:停留在原页面,提示密码错误,用户需要再次输入

具体看/src/login部分源码吧~

值得注意的是:跳转页面采用useNavigate

自动校验token

我这里采取的是,在login页面渲染的时候发送自动校验的请求,目前只想到这个~

登出页面

我主要设置在home组件里面,登出就很简单,要做的就是:

  1. 删除sessionStorage里面的token
  2. 跳转到登录页面(非必要!)

优化思考

优化1: 考虑设置token的有效时长

优化2: 考虑组件间传值

比如用户登陆后可以在home组件访问到是谁登录的,欢迎XXX诸如此类

知识点总结

  • 登录流程
  • antd组件应用
  • axios请求相关:封装、请求头设置、发请求、拦截器等
  • 跨域
  • react-router:基本配置,跳转路由
  • token相关
  • cookie sessionStorage localStorage

参考

antd

styled-components

(干货) 全网最全 react-router-dom v6.0学习指南