Closed Mr-Sloth closed 5 years ago
Nice suggestions @darklinki, I have one improvement, if a user is not allowed to access a Menu Entry, this entry should be hidden !
Have a look at #151
Ah thank you @sharath1608 . Would be nice to have this as example in the project. Disaple one entry and set the style different is also working.
@darklinki Agree, not sure if it's part of the doc . But just to illustrate it, you can hide a menu item like this
{
path: 'metrics/:id',
data: {
menu: {
title: 'Metrics',
icon: 'ion-stats-bars',
hidden:true,
selected: false,
expanded: false,
order: 200,
}
}
},
I am implementing user role management, to hide menu entries for unauthorized users. I will share my contributions as soon as I am done.
@m0uj any update on the role management?
I also need role base manu hidden machanism. @m0uj have you any update
If he doesn´t replys until next week, I will build a simple one cause I would need it anyway in a few weeks. You guys only need a simple role management or also a login/register system ?
I have the same requirement for the hiding the menu based on user role. some of the menus are only available for super admin. I did protect the route, but I need some mechanism to hide the menu as well. @darklinki do you have any updates?
it is possible to implementate it easy.
First solution, in pages.component ngOnInit() before you send the array to the service you can manipulate it with your user permissions
Second solution, in the BaMenuService, there are a lot of functions to manipulate the menu like selectMenuItem. easy implement one funktion to skip items
Last solution, implement a function in the itemComponent to hide himself if the user have no permissions
@crossRT I have a working solution, kinda like newmans solution.
I think I read something about this feature in the ngx branch.
this is how I achieve it.
in baMenuService.ts
line 111, I change prepared.hidden
to true
when logged in user doesn't have the role.
// hide menu when user doesn't have the role and permissions.
if (prepared.roles && prepared.roles.length > 0) {
const role = this.authService.getUser().role;
if (prepared.roles.indexOf(role) === -1) {
prepared.hidden = true;
}
}
and here's the menu:
{
path: 'user',
data: {
menu: {
title: 'kuber.user',
icon: 'ion-android-person-add',
selected: false,
expanded: false,
order: 0,
roles: ['super_admin']
}
}
},
@crossRT, Its working like a charm..thanks
disable: true
Menu points should be written in grey. This would make it possible to show user permisions already in the menu. E.g user X is not allowed to acces dashboard so its written in grey and he can´t click on it.
....Please implement this feature
Hi all, I've tried your solutions with some changes according to my project. It's working but with one major issue in it I'm facing is that I've to refresh browser for menu to hide or show according to user role. My pages-menu.ts file is:
import { NbMenuItem } from '@nebular/theme';
import * as _ from 'lodash';
import decode from 'jwt-decode';
const roles = [1, 2, 3, 4, 5, 6, 7];
const token = localStorage.getItem('auth_app_token');
// decode the token to get its payload
let tokenPayload: any = [];
if (token) {
tokenPayload = decode(token);
}
export const MENU_ITEMS: NbMenuItem[] = [
{
title: 'Utahrunning',
link: '#',
children: [
{
title: 'Ask An Expert Question',
icon: 'nb-compose',
link: '/admin/askquestion',
hidden: !findRole([1, 2, 7], Number(tokenPayload.userRole)),
},
{
title: 'Dashboard',
icon: 'nb-home',
link: '/admin/dashboard',
hidden: !findRole([1, 2], Number(tokenPayload.userRole)),
home: true,
},
{
title: 'Settings',
icon: 'ion-wrench',
link: '/admin/settings',
hidden: !findRole([1], Number(tokenPayload.userRole)),
children: [
{
title: 'Search',
link: '/admin/settings/search',
},
{
title: 'Notification',
link: '/admin/settings/notification',
},
]
},
]
},
];
function findRole(allowedRoles, userRole) {
if (Number.isNaN(userRole)) {
return false;
}
console.log('testing -- ' + userRole);
return (_.find(allowedRoles, function (
item: any
) {
return item == userRole;
})) ? true : false;
}
After login findRole didn't run and I've to refresh browser then correct menu loads up. If I logout and login from different user having different role then it shows menu appeared for previously logged in user and again I've to refresh. How can I handle this or if I'm missing anything? Thanks!
Hi all, I've tried your solutions with some changes according to my project. It's working but with one major issue in it I'm facing is that I've to refresh browser for menu to hide or show according to user role. My pages-menu.ts file is:
import { NbMenuItem } from '@nebular/theme'; import * as _ from 'lodash'; import decode from 'jwt-decode'; const roles = [1, 2, 3, 4, 5, 6, 7]; const token = localStorage.getItem('auth_app_token'); // decode the token to get its payload let tokenPayload: any = []; if (token) { tokenPayload = decode(token); } export const MENU_ITEMS: NbMenuItem[] = [ { title: 'Utahrunning', link: '#', children: [ { title: 'Ask An Expert Question', icon: 'nb-compose', link: '/admin/askquestion', hidden: !findRole([1, 2, 7], Number(tokenPayload.userRole)), }, { title: 'Dashboard', icon: 'nb-home', link: '/admin/dashboard', hidden: !findRole([1, 2], Number(tokenPayload.userRole)), home: true, }, { title: 'Settings', icon: 'ion-wrench', link: '/admin/settings', hidden: !findRole([1], Number(tokenPayload.userRole)), children: [ { title: 'Search', link: '/admin/settings/search', }, { title: 'Notification', link: '/admin/settings/notification', }, ] }, ] }, ]; function findRole(allowedRoles, userRole) { if (Number.isNaN(userRole)) { return false; } console.log('testing -- ' + userRole); return (_.find(allowedRoles, function ( item: any ) { return item == userRole; })) ? true : false; }
After login findRole didn't run and I've to refresh browser then correct menu loads up. If I logout and login from different user having different role then it shows menu appeared for previously logged in user and again I've to refresh. How can I handle this or if I'm missing anything? Thanks!
Did you managed to find the issue here - regarding the cached menu on logout and login with another role?
Thanks, Ovi
Hi @rovidiu did you have a look at https://akveo.github.io/nebular/docs/security/acl-configuration--usage
Because when i look at your code i think you have the wrong approach.
Hi @rovidiu did you have a look at https://akveo.github.io/nebular/docs/security/acl-configuration--usage
Because when i look at your code i think you have the wrong approach.
Hello, I wrote that document, but *How to use _nbIsGranted_ directive for menu**? Same @umairm638 issue, I problem with showing menu during switch user? Can you show a sample/code to us?
I solved this by creating a menu service:
`import { Injectable } from '@angular/core'; import { NbMenuItem } from '@nebular/theme'; import { NbAccessChecker } from '@nebular/security';
@Injectable({ providedIn: 'root' }) export class MenuService { constructor(private accessChecker: NbAccessChecker) { } findMenuItem(dataToFind:string, menuItems: NbMenuItem[]):NbMenuItem { return menuItems.find(t=>t.data == dataToFind); }
getSubMenuItem = function (data:string, subMenuItems:NbMenuItem[]) { if (subMenuItems) { for (var i = 0; i < subMenuItems.length; i++) { if (subMenuItems[i].data == data) { return subMenuItems[i]; } var found = this.getSubMenuItem(data, subMenuItems[i].children); if (found) return found; } } };
setMenuItemVisibility(dataToFind:string, permission:string, resource:string, menuItems: NbMenuItem[]){ var menuItem = this.getSubMenuItem(dataToFind, menuItems); console.log('menu searched:' + dataToFind); console.log('menu found:' + menuItem); if(menuItem == null)return; console.log('setting auth for menu:' + menuItem.data); this.accessChecker.isGranted(permission, resource).subscribe(res=>{ menuItem.hidden = !res }); }
} `
and used it within pages.component.ts : `import { Component } from '@angular/core';
import { MENU_ITEMS } from './pages-menu'; import {MenuService} from '../services/menu.service' import { NbAccessChecker } from '@nebular/security';
@Component({ selector: 'ngx-pages', template: `
, }) export class PagesComponent { menu = MENU_ITEMS; constructor( private accessChecker: NbAccessChecker, private menuService:MenuService){ console.log('menu items auth'); menuService.setMenuItemVisibility('createuser', 'create', 'users', this.menu); } }
you should define 'data' property for your menu items like :
{ icon: 'nb-plus', title: 'Create User', link: '/pages/users/create-user', data: 'createuser' },
i am facing issue with hiding menu,in our project they are five roles,i need hide based on user role,can any one help me with that
Same here, I have to refresh the browser in order to load the correct menu for current user logged.
initMenu() {
let userRole: string;
this.roleProvider.getRole().subscribe(role => userRole = role);
this.pagesMenu
.getMenu(userRole)
.pipe(takeWhile(() => this.alive))
.subscribe(menu => {
this.menu = menu;
});
}
userRole
does not change its value when you log in with different user (and different role) unless you refresh the browser.
I am using custom authentication. If you want to use NbAccessChecker instead of custom authentication check out the commented code.
I have this in my pages.component.ts
import { Component } from '@angular/core'; import { MENU_ITEMS } from './pages-menu'; import { AuthService } from '../core/auth/services/auth.service'; import { NbAccessChecker } from '@nebular/security'; import { NbMenuItem } from '@nebular/theme';
@Component({ selector: 'ngx-pages', styleUrls: ['pages.component.scss'], template: `
`, }) export class PagesComponent {
menu = MENU_ITEMS;
constructor(private accessChecker: NbAccessChecker, public auth: AuthService) {
}
ngOnInit() { this.authMenuItems(); }
authMenuItems() { this.menu.forEach(item => { this.authMenuItem(item); }); }
authMenuItem(menuItem: NbMenuItem) { if (menuItem.data && menuItem.data['expectedRoles']) { menuItem.hidden = !this.auth.isAuthorized(menuItem.data['expectedRoles']);
} else {
menuItem.hidden = true;
}
if (!menuItem.hidden && menuItem.children != null) {
menuItem.children.forEach(item => {
if (item.data && item.data['expectedRoles']) {
item.hidden = !this.auth.isAuthorized(menuItem.data['expectedRoles']);
} else {
// if child item do not config any `data.permission` and `data.resource` just inherit parent item's config
item.hidden = menuItem.hidden;
}
});
}
}
// authMenuItem(menuItem: NbMenuItem) {
// if (menuItem.data && menuItem.data['permission'] && menuItem.data['resource']) {
// this.accessChecker.isGranted(menuItem.data['permission'], menuItem.data['resource']).subscribe(granted => {
// menuItem.hidden = !granted;
// });
// } else {
// menuItem.hidden = true;
// }
// if (!menuItem.hidden && menuItem.children != null) {
// menuItem.children.forEach(item => {
// if (item.data && item.data['permission'] && item.data['resource']) {
// this.accessChecker.isGranted(item.data['permission'], item.data['resource']).subscribe(granted => {
// item.hidden = !granted;
// });
// } else {
// // if child item do not config any data.permission
and data.resource
just inherit parent item's config
// item.hidden = menuItem.hidden;
// }
// });
// }
// }
}
Thanks!
I was able to achieve it by getting the user role with a custom service rather than getRole
provided by RoleProvider
.
users.service.ts
getCurrentUser(): Observable<User> {
return this.authService.isAuthenticated().pipe(
switchMap(authenticated => {
return authenticated ? this.api.getCurrent() : of(null);
}),
);
}
pages.component.ts
initMenu() {
this.usersService.getCurrentUser().subscribe(user => {
this.pagesMenu
.getMenu(user.role)
.pipe(takeWhile(() => this.alive))
.subscribe(menu => {
this.menu = menu;
});
});
}
@sharath1608 you saved my day I was able to dynamically add this HIDDEN attribute on every menu item and their children
Thanks
I'm submitting a ... [ ] bug report [x] feature request [ ] question about the decisions made in the repository
Do you want to request a feature ?
To make it easier working with the project as starter it would be nice if we have 2 new options in pages.menu.
hidden: true, false
disable: true
I build this ugly by my own, but I´m sure more people would have a use of it.
Pages.menu and pages.routing contain the Pages. To remove one you have to change both files.