在使用React-admin
框架的时候,碰到这样一个需求,也不能说是需求吧,应该是产品的共性。问题是:当我登陆之后,打开新的标签页TAB(通常是在登陆的主页面上,有些模块会在列表中加上链接,按下Ctrl和鼠标左键,会打开一个新的TAB页面),那么在新页面中应该能和上一个登陆之后的页面共享登陆状态。
但是在React-admin
默认使用的是sessionstorage
来保存保存登陆的数据,如下是React-admin
框架自带的设置登陆用户的方法:
/**
* 设置当前用户信息
* @param loginUser 当前登录用户信息
*/
export function setLoginUser(loginUser = {
}) {
// 将用户属性在这里展开,方便查看系统都用到了那些用户属性
const {
id, name, avatar, token, permissions, menus, groupmenus, grouppermissions, ...others } = loginUser;
const userStr = JSON.stringify({
id, // 用户id 必须
name, // 用户名 必须
avatar, // 用头像 非必须
token, // 登录凭证 非必须 ajax请求有可能会用到,也许是cookie
permissions, // 用户权限
grouppermissions, // 分权权限
menus, // 用户的菜单
groupmenus, // 分权管理菜单
...others, // 其他属性
});
sessionStorage.setItem(LOGIN_USER_STORAGE_KEY, userStr);
}
而且在对路由进行控制的时候确实也是根据登陆用户进行判断的,代码如下:
在其保持认证路由的代码中通过!noAuth && !isLogin()
去控制你新打开TAB页
是否需要重新定向到登录页面的判断。
而在isLogin
中可以看到:
/**
* 获取当前用户信息
* @returns {any}
*/
export function getLoginUser() {
const loginUser = sessionStorage.getItem(LOGIN_USER_STORAGE_KEY);
return loginUser ? JSON.parse(loginUser) : null;
}
/**
* 判断用户是否登录 前端简单通过登录用户是否存在来判断
* @returns {boolean}
*/
export function isLogin() {
// 如果当前用户存在,就认为已经登录了
console.log("getLoginUser",getLoginUser())
return !!getLoginUser();
}
是根据sessionStorage.getItem(LOGIN_USER_STORAGE_KEY)
方式去获取的当前登录用户,我们知道session只在当前窗口中是共享的,所以当我们新打开一个窗口的时候,就获取不到之前的sessionStorage
中的数据,导致会重新定向到登录页面,无法共享登陆状态。
为了解决这个问题,我们不得不引入localStorage
来解决这个问题,达到在整个浏览器中都能共享登陆状态的目的。
基于此我们需要对React-admin
框架进行改造。讲过上面的代码分析,思路便出来了:所有的关键点都指向了获取用户这个方法,那么想要获取到上一个页面的登陆状态,就需要优先从locastorage中获取用户信息,然后再去sessionstorage中去获取用户信息。那么我们就需要在用户登录成功后去同时设置locastorage和sessionstorage。而sessionstorage的设置就是调用框架提供的setLoginUser方法即可。对于locastorage的设置用户的方法,你需要注意的是,你不需要额外创建一个key保存用户信息。需要通过localStorage.setItem(LOGIN_USER_STORAGE_KEY,userStr)来设置
。
为什么要这么做呢? 我随便找一个key去设置localStorage.setItem("user,xxxx)
不也可以么?
如果你在登陆之后去设置,就会出现编译不通过就是一个json异常的问题,因为在这里会出现异常:
而且我们可以在登出函数中看到这么个函数是将localStorage中的用户清空的
,这也就是说我们在保存用户的信息的时候也要使用localStorage.setItem(LOGIN_USER_STORAGE_KEY,userStr)
:
所以我们要做的有这么几点: