Full Angular RBAC + Permission System (ULTIMATE)
Full Angular RBAC + Permission System (ULTIMATE)
You will get:
- ✅ Backend-driven Roles + Permissions
- ✅ Angular stores user access
- ✅ Dynamic menus (Task C)
- ✅ Route guard (Task D)
- ✅ API protection (Task E)
- ✅ Admin can assign permissions (concept)
- ✅ Supports Permission Groups, Feature Flags, Multi-role users
- ✅ Clean enterprise architecture
🧠 Enterprise Concept (Real World)
After login, backend returns:
{
"userId": 101,
"name": "Sai",
"roles": ["Admin"],
"permissions": [
"DASHBOARD_VIEW",
"USERS_VIEW",
"USERS_CREATE",
"REPORTS_VIEW",
"SETTINGS_VIEW"
]
}
Angular uses this for:
- Menu show/hide
- Route guard
- API guard
- UI button enable/disable
1️⃣ Auth State Model (Enterprise)
// auth-state.model.ts
import { Permission, Role } from './permission.model';
export interface AuthUser {
userId: number;
name: string;
roles: Role[];
permissions: Permission[];
}
2️⃣ AuthStore Service (Central State)
BEST enterprise pattern using BehaviorSubject.
// auth-store.service.ts
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
import { AuthUser } from './auth-state.model';
@Injectable({ providedIn: 'root' })
export class AuthStoreService {
private userSubject = new BehaviorSubject(null);
user$ = this.userSubject.asObservable();
setUser(user: AuthUser) {
this.userSubject.next(user);
}
getUser(): AuthUser | null {
return this.userSubject.value;
}
clearUser() {
this.userSubject.next(null);
}
}
3️⃣ Update PermissionService to use AuthStore
// permission.service.ts
import { Injectable } from '@angular/core';
import { AuthStoreService } from './auth-store.service';
import { Permission, Role } from './permission.model';
@Injectable({ providedIn: 'root' })
export class PermissionService {
constructor(private authStore: AuthStoreService) {}
private get roles(): Role[] {
return this.authStore.getUser()?.roles ?? [];
}
private get permissions(): Permission[] {
return this.authStore.getUser()?.permissions ?? [];
}
hasPermission(permission: Permission): boolean {
return this.permissions.includes(permission);
}
hasAnyPermission(permissions: Permission[]): boolean {
return permissions.some(p => this.hasPermission(p));
}
isInRole(role: Role): boolean {
return this.roles.includes(role);
}
}
4️⃣ Login Flow: Store User + Tokens
// auth.service.ts (login part)
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable, tap } from 'rxjs';
import { TokenService } from './token.service';
import { AuthStoreService } from './auth-store.service';
import { AuthUser } from './auth-state.model';
export interface LoginResponse {
accessToken: string;
refreshToken: string;
user: AuthUser;
}
@Injectable({ providedIn: 'root' })
export class AuthService {
private baseUrl = 'https://localhost:5001/api/auth';
constructor(
private http: HttpClient,
private tokenService: TokenService,
private authStore: AuthStoreService
) {}
login(email: string, password: string): Observable {
return this.http.post(`${this.baseUrl}/login`, { email, password }).pipe(
tap(res => {
this.tokenService.setTokens(res.accessToken, res.refreshToken);
this.authStore.setUser(res.user);
})
);
}
logout() {
this.tokenService.clearTokens();
this.authStore.clearUser();
window.location.href = "/login";
}
}
5️⃣ Persist User on Refresh (IMPORTANT)
Store user in localStorage to survive browser refresh:
// auth-store.service.ts (upgrade)
private userKey = "auth_user";
setUser(user: AuthUser) {
localStorage.setItem(this.userKey, JSON.stringify(user));
this.userSubject.next(user);
}
loadUserFromStorage() {
const data = localStorage.getItem(this.userKey);
if (data) {
this.userSubject.next(JSON.parse(data));
}
}
clearUser() {
localStorage.removeItem(this.userKey);
this.userSubject.next(null);
}
6️⃣ Call loadUserFromStorage() in App Startup
// app.component.ts
import { Component } from '@angular/core';
import { AuthStoreService } from './core/auth/auth-store.service';
@Component({
selector: 'app-root',
template: ` `
})
export class AppComponent {
constructor(private authStore: AuthStoreService) {
this.authStore.loadUserFromStorage();
}
}
7️⃣ RBAC: Button Level Permissions
Example: Hide "Create User" button if no permission.
// users.component.html
8️⃣ Ultimate: Feature Module Protection
// users-routing.module.ts
const routes: Routes = [
{
path: '',
canActivate: [PermissionGuard],
data: { permissions: ['USERS_VIEW'] },
component: UsersListComponent
},
{
path: 'create',
canActivate: [PermissionGuard],
data: { permissions: ['USERS_CREATE'] },
component: UsersCreateComponent
}
];
9️⃣ Ultimate: Backend Driven Menu (REAL Enterprise)
Instead of hardcoding menu config, backend returns:
[
{
"label": "Dashboard",
"route": "/dashboard",
"icon": "dashboard",
"permissions": ["DASHBOARD_VIEW"]
}
]
Angular filters and shows menu items dynamically.
🔟 Backend Database Design (Interview Gold)
Tables:
- ✅ Users
- ✅ Roles
- ✅ Permissions
- ✅ UserRoles
- ✅ RolePermissions
- ✅ RefreshTokens
🔥 11️⃣ Permission Groups (MEGA Enterprise)
Instead of 100 permissions, group them:
- USERS: VIEW, CREATE, UPDATE, DELETE
- REPORTS: VIEW, EXPORT
- SETTINGS: VIEW, UPDATE
🔥 12️⃣ Full Enterprise Flow Summary
- Login: Get tokens + roles + permissions, save to storage, load on refresh
- UI: Menu filtered, buttons hidden, routes blocked, APIs protected
- Token expiry: Refresh token interceptor retries automatically
⭐ Interview One-Liner (SUPER STRONG)
I implemented a complete RBAC system in Angular where permissions from backend control UI menus, route access, button visibility, and API calls using directives, guards, interceptors, and centralized auth store.
Comments
Post a Comment