背景
最近开发了两个工具性小项目(迁移工具、备份工具),本身在需求上没有登陆、退出、鉴权一系列功能。然而临近交付,客户又提出一点小小的安全要求,要有登录、退出,又要超时退出。这种在临交付之前的既要又要
,只能做最简单的登录认证体系。
登录·退出
因为存在操作日志
的缘故,只能以接口形式实现,服务端还需一点点介入。服务端接口只进行简单的账号/密码对比,Token管理放到客户端处理。
登录
输入超管账号/密码完成登录,登录成功后生成uuid作为Token设置进Cookie
。
handleLogin = (err, values) => {
const { dispatch, login } = this.props;
dispatch({
type: 'user/login',
payload: { user: values?.account, passwd: values.password },
callback() {
// 构建唯一uuid作为Token
setAccessToken(uuid());
// 登录成功,直接跳转首页
history.replace('/');
},
errorback() {
notification.error({ message: '账号/密码错误' });
},
});
};
设置Cookie
征求客户意见后,空闲后过期时间设置为1小时
// 设置1小时过期的Cookie
export function setAccessToken(str) {
// 获取当前时间
const now = new Date();
// 计算60分钟后的时间
const oneMinuteLater = new Date(now.getTime() + (60 * 60 * 1000));
return Cookies.set('access_token', str, { expires: oneMinuteLater });
}
退出
退出操作,清理Token并跳转到登录页
dispatch({
type: 'user/logout',
callback() {
removeAccessToken();
history.replace('/user/login');
},
errorback() {
notification.error({ message: '退出失败' });
},
});
Token超时退出
超时退出模拟服务端实现的机制,在用户有操作的情况下Token过期时间后延,只有在系统空闲场景下,1小时后退出。
区分系统繁忙·空闲
繁忙
:系统存在用户手动操作的接口访问空闲
:系统不存在用户手动操作的接口访问
有简单的概念定义后,甄别所有类别接口,系统存在用户手动操作的接口访问定义为:
- 非轮询访问的接口
- 非退出接口
更新Token过期时间
系统在用户操作接口,并请求成功的场景下,顺延1小时过期时间。在Http拦截器中处理如下,Cookies中Token一旦过期,记录就会获取为空,跳转登录页。如果是定义的繁忙
操作,执行更新Token超时操作。
const ignoreCheckTokenApi = ['/users/logout'];
return fetch(url, newOptions).then((response) => {
const currentToken = getAccessToken();
if (!currentToken) {
history.replace('/user/login');
}
// 非轮询接口,排除退出接口,更新Cookie中Token超时间
if(!newOptions?.headers?.isPolling && !ignoreCheckTokenApi.some((v) => newUrl.includes(v))) {
setAccessToken(currentToken);
}
}
优化思路
可能会存在一个页面存在并发访问很多接口的场景,可以在合并更新方向优化,经过简单测试发现并没有对性能有什么影响,大写的OK。
后记
只适合简单、安全要求不高的项目,构建一种麻雀虽小肝胆俱全的安全要求。