模版中是登录后直接就返回admin或者user,把这两个作为权限放在localStorage中
实际项目中先要去拿到token,再根据token去拿用户权限
文档中说使用 localstorage 模拟权限角色,实际项目中可能需要从后台读取。
这是要把getAuthority, RenderAuthorized 都改成async方法吗?
Translation of this issue:
The template is directly returned after the login admin or user, put these two as permissions in localStorage
The actual project must first get the token, then according to the token to get user rights
The documentation says that using localstorage to simulate a privilege role may require reading from the background in real projects.
Is this to change getAuthority, RenderAuthorized to async method?
我现在把utils\authority.js的getAuthority改成这样
export async function getAuthority() {
const accessToken = getAccessToken();
try {
const response = await fetch(`http://localhost:9595/user?access_token=${accessToken}`);
return await response.json();
} catch (e) {
return [ 'user', 'admin' ];
}
}
renderAuthorize改成这样
const renderAuthorize = (currentAuthority) => {
if (currentAuthority) {
if (currentAuthority.constructor.name === 'Function') {
CURRENT = currentAuthority();
}
if (currentAuthority.constructor.name === 'String') {
// CURRENT = currentAuthority;
CURRENT = [ currentAuthority ];
}
if (currentAuthority.constructor.name === 'Array') {
CURRENT = currentAuthority;
}
if (currentAuthority.constructor.name === 'Promise') {
currentAuthority.then((result) => {
CURRENT = result;
});
}
} else {
// CURRENT = ['NULL'];
CURRENT = [];
}
return Authorized;
};
结果是checkPermissions时currentAuthority都还是空的
遇到相同的问题了,关注+1
来个大佬解决一下
我现在改成了login完就去取权限,然后把权限保存到sessionStorage中
*login({ payload }, { call, put }) {
const loginInfo = yield call(serviceLogin.login, payload);
yield put({
type: 'changeLoginStatus',
payload: { loginInfo },
});
if (!loginInfo || loginInfo.error) {
return;
}
// 取权限
const respMe = yield call(serviceLogin.me);
if (!respMe || respMe.error) {
yield put({
type: 'setError',
payload: { respMe },
});
return;
}
setMe(respMe.data);
// Login successfully
reloadAuthorized();
yield put(routerRedux.push('/'));
},
但是sessionStorage不能跨标签页使用,再开一个标签页就又要登录了,之后我找了shared-session-storage这个插件,说是可以解决sessionStorage在标签页共享的问题,我在react工程中试了没问题,但在antd pro里还是不行
从网上找了个共享sessionStorage的方法
/**
* 因为sessionStorage在多个浏览器标签页中不能共享,该方法可以让sessionStorage在多个标签页中共享使用
*/
export default function shareSession() {
if (!sessionStorage.length) {
// Ask other tabs for session storage
localStorage.setItem('getSessionStorage', Date.now());
}
// 对操作localStorage和sessionStorage进行监听
window.addEventListener('storage', (event) => {
// 如果localStorage中存入了getSessionStorage
if (event.key === 'getSessionStorage') {
localStorage.setItem('sessionStorage', JSON.stringify(sessionStorage));
localStorage.removeItem('sessionStorage');
} else if (event.key === 'sessionStorage' && !sessionStorage.length) {
const data = JSON.parse(event.newValue);
for (const key in data) {
if ({}.hasOwnProperty.call(data, key)) {
sessionStorage.setItem(key, data[key]);
}
}
}
});
}
在index.js中所有方法之前调用
shareSession();
// 1. Initialize
const app = dva({
history: createHistory(),
});
但在RenderAuthorized时getAuthority()依然是空的
打开调试的时候看sessionStorage是有值的
这说明这个shareSession还是执行到getAuthority后面了
还请详细讲讲处理的思路吧
setAuthority 会将login时的权限保存到localstorage中,顶层路由中有个权限数组是判断准入原则的,进入后,路由配置menu中的权限是配置侧边栏的数据,权限匹配就展示,单个权限配置成字符串,多个权限配成数组,没有权限配置就是默认都加载
文档中说使用 localstorage 模拟权限角色,这个没有任何问题吧。确实是你用token 去取到用户权限后,然后保留就可以了,不知道你们的问题在哪里?我们公司的ERP信息平台,10多种身份的权限控制,以及内容板块的控制,都没啥问题。不得不说ant design 组件确实写的很不错。给力
localstorage是用来模拟权限的,实际项目中最好不要使用, 这个权限主要是通过 Authorized.js reloadAuthorized方法进行刷新和存储.
我这边是这样改造的:
1.修改reloadAuthorized方法增加 authority 参数
// Reload the rights component
const reloadAuthorized = (authority) => {
Authorized = RenderAuthorized(authority);
};
2.修改models/user.js:*fetchCurrent, 调用reloadAuthorized重新加载 Authorized
const info = yield call(fetchSessionInfo);
reloadAuthorized(info.permissions);
yield put({
type: 'saveCurrentUser',
payload: info,
});
如果 permissions 是数组,权限校验的改造可参看 https://github.com/ant-design/ant-design-pro/issues/1276
@yjy8749 你的权限是放在sessionStorage中的还是。 直接放到store里面的?
@yjy8749 你每次需要权限更新的地方都重新取权限?还是在登录的时候缓存了权限?
@roc2539 准确的来说是放在 Authorized 变量中, 登录后重新初始化 Authorized 变量, 你看下 Authorized.js 的实现就懂了
噢,明白了。 @yjy8749
有没有可能,后端负责存储权限,前端只负责根据后端传过来的权限列表,渲染前端菜单呢?
我看现在前端的菜单好像是通过common/menu.js来配置,后端传过来的是角色,而角色和每个菜单的关系,前端还要再次判断。
我的意思是,登录后后端响应到前端一个menu数组。前端在getRouterData方法里,调用getMenuData方法的时候,把后端的这个数组传过去。getMenuData只返回数组中有的菜单项。
后端也可以对每个菜单项对应页面的所有操作项进行配置,返回给前端。这个的控制由每个组件自行控制,但要把这个配置传给组件。
这样的思路,前端只接受后端固定的数据格式返回。由后端来生成完整的权限集合。角色和权限的关系只需要在后端保存一份。
而现在的逻辑,其实我看不太懂,但是getRouterData这个方法貌似就只调用了一次,把所有的菜单都加载进去了(在这个方法里,貌似同时通过routerConfig的时候就把路由全部注册了,感觉这个方法起名不太好)。
我搞后端的前端知识不够完善,搞不完全明白,可以讨论一下么?

根据我的思路实现了一个版本,我的fork
我去掉了原有的Authorized相关的组件,在BasicLayout中,传给SiderMenu的菜单配置,是经过filter的。
用户具有的权限,保存在currentUser.privilege,这个值可以在用户登录后一并由后端返回。
发现了奇怪的问题。貌似打开页面的时候,菜单还是全部出来了,调整一下页面大小,貌似会触发页面刷新,然后就正常了。。
@yjy8749 你这样存在变量中的实现跟存在sessionStorage中的效果是一样的吧.
在这个标签页中登录了,如果我copy路径,再打开一个新标签页又会跳到登录界面了.
我现在是把权限保存在cookie中了
@ilaipi antd pro这个demo判断的是角色,我觉得你不应该删掉Authorized相关组件,而是修改getRouterData方法,将方法中之前写死的路径和权限通过后端加载
@shadiniao 我要删掉Authorized相关的组件,我是改了整个的认证机制,不需要前端来对每个菜单再做权限判断。后端返回给前端的是完整的用户拥有的权限。所以过滤后的menuData,就是用户可操作的菜单,不再需要前端再根据角色来判断(不然前端还要维护菜单和角色的关系)。
我觉得权限可以分两层来。一层是菜单级,就是用户能操作哪些菜单。第二层是每个菜单能操作的操作项,比如某个按钮要不要显示。第二层配置也让后端传过来。
从更安全的角度,后端可以再对请求做一次权限认证。如果用户没有权限,可以返回403,前端统一处理,碰到403就跳转到登录。
@shadiniao 不会的,重新打开一个标签页的话,这时候会重新调用 fetchCurrent 重新初始化 Authorize
@ilaipi 我也觉得应该后端处理 他们非把权限用前端处理 你这个影响面包屑吗
@mcmf 不影响的,你看我的截图,就是我实现出来的样子。最新的提交我已经修复了菜单老是不按照权限加载的问题。
@yjy8749 你好,按照你的这种方法,已经登陆成功后,刷新页面,此时先加载'./src/router.js',里面使用了AuthorizedRoute组件来判断权限,并决定是否重定向至‘/user/login’,此时还来得及*fetchCurrent,因此AuthorizedRoute还没有被更新,因此,肯定会被重定向,无法做到记住登陆了。囧
@USTCLX 我这边是做了这样的处理的,如果 fetchCurrent 没有完成,整个页面都会显示加载中,只有等到 fetchCurrent 执行完成后, 才会渲染页面, 你试试
@shadiniao 不会的,重新打开一个标签页的话,这时候会重新调用 fetchCurrent 重新初始化 Authorize
您好,我遇到的问题是:在重新打开一个页面的时候,变量清空,权限为空,然后进入不到fetchCurrent 的页面。在进入页面之前,找不到合适的位置进行 更新权限。
真实项目权限就不应该由前端来控制,
菜单列表,和每次操作请求都应该是由后端来生成和校验。
框架提供的认证机制,应该看做只是为了demo的完整性
@shadiniao 我要删掉
Authorized相关的组件,我是改了整个的认证机制,不需要前端来对每个菜单再做权限判断。后端返回给前端的是完整的用户拥有的权限。所以过滤后的menuData,就是用户可操作的菜单,不再需要前端再根据角色来判断(不然前端还要维护菜单和角色的关系)。我觉得权限可以分两层来。一层是菜单级,就是用户能操作哪些菜单。第二层是每个菜单能操作的操作项,比如某个按钮要不要显示。第二层配置也让后端传过来。
从更安全的角度,后端可以再对请求做一次权限认证。如果用户没有权限,可以返回
403,前端统一处理,碰到403就跳转到登录。
你这个也只是菜单的过滤,本地的routes,还是渲染了react-router-dome的Route的。
@shadiniao 我要删掉
Authorized相关的组件,我是改了整个的认证机制,不需要前端来对每个菜单再做权限判断。后端返回给前端的是完整的用户拥有的权限。所以过滤后的menuData,就是用户可操作的菜单,不再需要前端再根据角色来判断(不然前端还要维护菜单和角色的关系)。
我觉得权限可以分两层来。一层是菜单级,就是用户能操作哪些菜单。第二层是每个菜单能操作的操作项,比如某个按钮要不要显示。第二层配置也让后端传过来。
从更安全的角度,后端可以再对请求做一次权限认证。如果用户没有权限,可以返回403,前端统一处理,碰到403就跳转到登录。你这个也只是菜单的过滤,本地的routes,还是渲染了react-router-dome的Route的。
那就是要想办法在渲染Route之前把权限加载进来。看看官方能不能支持从后端加载权限配置,可以选择是写在前端还是从后端获取
Most helpful comment
@shadiniao 我要删掉
Authorized相关的组件,我是改了整个的认证机制,不需要前端来对每个菜单再做权限判断。后端返回给前端的是完整的用户拥有的权限。所以过滤后的menuData,就是用户可操作的菜单,不再需要前端再根据角色来判断(不然前端还要维护菜单和角色的关系)。我觉得权限可以分两层来。一层是菜单级,就是用户能操作哪些菜单。第二层是每个菜单能操作的操作项,比如某个按钮要不要显示。第二层配置也让后端传过来。
从更安全的角度,后端可以再对请求做一次权限认证。如果用户没有权限,可以返回
403,前端统一处理,碰到403就跳转到登录。