增加会话超时提示用户输入密码

release
Jimmy Liow 2 years ago
parent d95a54d5be
commit 03febbbc45

@ -29,8 +29,10 @@ class Auth {
return postForm(postUrl, formData)
.then(json => {
if (json.errcode == 0) {
this.login.token = json.Result.token;
this.login.timeout = false;
runInAction(() => {
this.login.token = json.Result.token;
this.login.timeout = false;
});
this.root.putSession(KEY_LOGIN_TOKEN, json.Result.token);
return json.Result.WU_LMI_SN;
} else {
@ -58,7 +60,7 @@ class Auth {
this.root.putSession(KEY_TRAVEL_AGENCY_ID, this.login.travelAgencyId);
this.root.putSession(KEY_USER_ID, this.login.userId);
});
this.startTokenInterval(this.login.token);
this.startTokenInterval();
return this.login;
} else {
throw new Error(json.errmsg + ': ' + json.errcode);
@ -66,11 +68,11 @@ class Auth {
});
}
startTokenInterval(loginToken) {
startTokenInterval() {
const authStore = this;
async function fetchLastRequet() {
const fetchUrl = prepareUrl(HT_HOST + '/service-CooperateSOA/GetLastReqDate')
.append('token', loginToken)
.append('token', authStore.login.token)
.build();
const json = await fetchJSON(fetchUrl)
if (json.errcode == 0 && isNotEmpty(json.result)) {
@ -80,26 +82,29 @@ class Auth {
}
}
setInterval(async () => {
async function checkTokenTimeout() {
const lastRequest = await fetchLastRequet();
console.info(lastRequest);
const lastReqDate = new Date(lastRequest);
const now = new Date();
const diffTime = now.getTime() - lastReqDate.getTime();
const diffMinute = diffTime/1000/60;
console.info(now);
console.info(lastReqDate);
console.info('diffTime: ' + diffTime);
console.info('diffMinute: ' + diffMinute);
if (diffMinute > 3) {
console.info('timeout...');
runInAction(() => {
authStore.login.timeout = true;
});
const diffHours = diffTime/1000/60/60;
if (diffHours > 4) {
authStore.logout();
}
}, 1000*60*1);
}
this.tokenInterval = setInterval(() => checkTokenTimeout(), 1000*60*20);
}
logout() {
this.root.clearSession();
runInAction(() => {
this.login.timeout = true;
});
}
tokenInterval = null;
changeUserPassword(password, newPassword) {
const formData = new FormData();
formData.append('UserID', this.login.userId);

@ -15,6 +15,15 @@ class Root {
makeAutoObservable(this);
}
clearSession() {
if (window.sessionStorage) {
const sessionStorage = window.sessionStorage;
sessionStorage.clear();
} else {
console.error('browser not support sessionStorage!');
}
}
getSession(key) {
if (window.sessionStorage) {
const sessionStorage = window.sessionStorage;

@ -1,5 +1,5 @@
import { Outlet, Link, useHref, useNavigate, NavLink } from "react-router-dom";
import { useEffect } from "react";
import { useEffect, useState } from 'react';
import { observer } from "mobx-react";
import { toJS } from "mobx";
import { Layout, Menu, ConfigProvider, theme, Dropdown, Space, Row, Col, Badge, Typography, Modal, Input, Button, App as AntApp } from "antd";
@ -25,13 +25,15 @@ const items = [
type: "divider",
},
{
label: <Link to="/login">Logout</Link>,
label: <Link to="/login?out">Logout</Link>,
key: "3",
},
];
function App() {
const [password, setPassword] = useState('');
const { authStore, noticeStore } = useStore();
const { notification } = AntApp.useApp();
const login = toJS(authStore.login);
const { noticeUnRead } = noticeStore;
const href = useHref();
@ -45,6 +47,30 @@ function App() {
}
}, [href]);
const onSubmit = () => {
authStore.valdateUserPassword(login.username, password)
.then(() => {
authStore.fetchUserDetail()
.catch(ex => {
notification.error({
message: `Notification`,
description: 'Failed to get user information.',
placement: 'top',
duration: 4,
});
});
})
.catch(ex => {
notification.error({
message: `Notification`,
description: ex.message,
placement: 'top',
duration: 4,
});
});
setPassword('');
};
const splitPath = href.split("/");
let defaultPath = "reservation";
@ -70,18 +96,18 @@ function App() {
closable={false}
maskClosable={false}
footer={null}
open={false}
// open={isModalOpen} onOk={handleOk} onCancel={handleCancel}
open={login.timeout}
>
<Title level={4}>Login timeout</Title>
<Title level={3}>Login timeout</Title>
<span>Please input your password</span>
<Space direction="horizontal">
<Input.Password addonBefore={login.username} />
<Input.Password value={password}
onChange={(e) => setPassword(e.target.value)}
onPressEnter={() => onSubmit()}
addonBefore={login.username} />
<Button
style={{
width: 80,
}}
onClick={() => setPasswordVisible((prevState) => !prevState)}
></Button></Space>
onClick={() => onSubmit()}
>Submit</Button></Space>
</Modal>
<Layout
@ -123,7 +149,9 @@ function App() {
<Dropdown
menu={{
items,
}}>
}}
trigger={['click']}
>
<a onClick={e => e.preventDefault()}>
<Space>
{authStore.login.username}

@ -1,15 +1,27 @@
import { useNavigate } from "react-router-dom";
import { useNavigate, useLocation } from "react-router-dom";
import { useEffect } from 'react';
import { Button, Checkbox, Form, Input, Row, App } from 'antd';
import { useStore } from '@/stores/StoreContext.js';
function Login() {
const { authStore,noticeStore } = useStore();
const { authStore, noticeStore } = useStore();
const { notification } = App.useApp();
const navigate = useNavigate();
const location = useLocation();
const [form] = Form.useForm();
useEffect (() => {
if (location.search === '?out') {
authStore.logout();
navigate('/login');
}
return () => {
// unmount...
};
}, []);
const onFinish = (values) => {
authStore.valdateUserPassword(values.username, values.password)
.then((userId) => {
@ -22,7 +34,7 @@ function Login() {
.catch(ex => {
notification.error({
message: `Notification`,
description: ex.message,
description: 'Failed to get user information.',
placement: 'top',
duration: 4,
});
@ -31,7 +43,7 @@ function Login() {
.catch(ex => {
notification.error({
message: `Notification`,
description: ex.message,
description: 'Login failed. Incorrect username or password.',
placement: 'top',
duration: 4,
});

@ -5,7 +5,6 @@ import { toJS } from "mobx";
import { Row, Col, Space, Button, Table, Input, Typography, DatePicker, Radio, Modal, App, Select } from 'antd';
import { useStore } from '@/stores/StoreContext.js';
import { DATE_PRESETS } from "@/config";
import dayjs from "dayjs";
const { Title } = Typography;
@ -91,7 +90,6 @@ function Newest() {
const location = useLocation();
const { reservationStore } = useStore();
const { reservationList, reservationPage, referenceNo, arrivalDateRange, cityList, cityGuideList } = reservationStore;
console.info(reservationPage);
const [isModalOpen, setIsModalOpen] = useState(false);
const [dataLoading, setDataLoading] = useState(false);
const { notification } = App.useApp();
@ -193,11 +191,11 @@ function Newest() {
</Modal>
<Space direction="vertical" style={{ width: '100%' }}>
<Title level={3}></Title>
<Row gutter={{ md: 24 }}>
<Col span={6}>
<Row gutter={16}>
<Col md={24} lg={6} xxl={4}>
<Input placeholder="Reference Number" value={referenceNo} onChange={(e) => { reservationStore.updatePropertyValue('referenceNo', e.target.value)} } />
</Col>
<Col span={18}>
<Col md={24} lg={8} xxl={6}>
<Space direction="horizontal">
Arrival Date
<DatePicker.RangePicker
@ -210,8 +208,10 @@ function Newest() {
reservationStore.updatePropertyValue('arrivalDateRange', dateRange == null ? [] : dateRange)
}}
/>
<Button type='primary' onClick={() => onSearchClick()} loading={dataLoading}>Search</Button>
</Space>
</Col>
<Col md={24} lg={4} xxl={4}>
<Button type='primary' onClick={() => onSearchClick()} loading={dataLoading}>Search</Button>
</Col>
</Row>
<Title level={3}></Title>

Loading…
Cancel
Save