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

release
Jimmy Liow 2 years ago
parent d95a54d5be
commit 03febbbc45

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

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

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

@ -1,4 +1,5 @@
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 { Button, Checkbox, Form, Input, Row, App } from 'antd';
import { useStore } from '@/stores/StoreContext.js'; import { useStore } from '@/stores/StoreContext.js';
@ -8,8 +9,19 @@ function Login() {
const { authStore, noticeStore } = useStore(); const { authStore, noticeStore } = useStore();
const { notification } = App.useApp(); const { notification } = App.useApp();
const navigate = useNavigate(); const navigate = useNavigate();
const location = useLocation();
const [form] = Form.useForm(); const [form] = Form.useForm();
useEffect (() => {
if (location.search === '?out') {
authStore.logout();
navigate('/login');
}
return () => {
// unmount...
};
}, []);
const onFinish = (values) => { const onFinish = (values) => {
authStore.valdateUserPassword(values.username, values.password) authStore.valdateUserPassword(values.username, values.password)
.then((userId) => { .then((userId) => {
@ -22,7 +34,7 @@ function Login() {
.catch(ex => { .catch(ex => {
notification.error({ notification.error({
message: `Notification`, message: `Notification`,
description: ex.message, description: 'Failed to get user information.',
placement: 'top', placement: 'top',
duration: 4, duration: 4,
}); });
@ -31,7 +43,7 @@ function Login() {
.catch(ex => { .catch(ex => {
notification.error({ notification.error({
message: `Notification`, message: `Notification`,
description: ex.message, description: 'Login failed. Incorrect username or password.',
placement: 'top', placement: 'top',
duration: 4, 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 { Row, Col, Space, Button, Table, Input, Typography, DatePicker, Radio, Modal, App, Select } from 'antd';
import { useStore } from '@/stores/StoreContext.js'; import { useStore } from '@/stores/StoreContext.js';
import { DATE_PRESETS } from "@/config"; import { DATE_PRESETS } from "@/config";
import dayjs from "dayjs";
const { Title } = Typography; const { Title } = Typography;
@ -91,7 +90,6 @@ function Newest() {
const location = useLocation(); const location = useLocation();
const { reservationStore } = useStore(); const { reservationStore } = useStore();
const { reservationList, reservationPage, referenceNo, arrivalDateRange, cityList, cityGuideList } = reservationStore; const { reservationList, reservationPage, referenceNo, arrivalDateRange, cityList, cityGuideList } = reservationStore;
console.info(reservationPage);
const [isModalOpen, setIsModalOpen] = useState(false); const [isModalOpen, setIsModalOpen] = useState(false);
const [dataLoading, setDataLoading] = useState(false); const [dataLoading, setDataLoading] = useState(false);
const { notification } = App.useApp(); const { notification } = App.useApp();
@ -193,11 +191,11 @@ function Newest() {
</Modal> </Modal>
<Space direction="vertical" style={{ width: '100%' }}> <Space direction="vertical" style={{ width: '100%' }}>
<Title level={3}></Title> <Title level={3}></Title>
<Row gutter={{ md: 24 }}> <Row gutter={16}>
<Col span={6}> <Col md={24} lg={6} xxl={4}>
<Input placeholder="Reference Number" value={referenceNo} onChange={(e) => { reservationStore.updatePropertyValue('referenceNo', e.target.value)} } /> <Input placeholder="Reference Number" value={referenceNo} onChange={(e) => { reservationStore.updatePropertyValue('referenceNo', e.target.value)} } />
</Col> </Col>
<Col span={18}> <Col md={24} lg={8} xxl={6}>
<Space direction="horizontal"> <Space direction="horizontal">
Arrival Date Arrival Date
<DatePicker.RangePicker <DatePicker.RangePicker
@ -210,8 +208,10 @@ function Newest() {
reservationStore.updatePropertyValue('arrivalDateRange', dateRange == null ? [] : dateRange) reservationStore.updatePropertyValue('arrivalDateRange', dateRange == null ? [] : dateRange)
}} }}
/> />
<Button type='primary' onClick={() => onSearchClick()} loading={dataLoading}>Search</Button>
</Space> </Space>
</Col>
<Col md={24} lg={4} xxl={4}>
<Button type='primary' onClick={() => onSearchClick()} loading={dataLoading}>Search</Button>
</Col> </Col>
</Row> </Row>
<Title level={3}></Title> <Title level={3}></Title>

Loading…
Cancel
Save