如何在Angular中实现通用的基于角色的路由权限控制?
Angular 基于角色的路由权限控制实现方案
一、扩展路由配置,添加角色元数据
在路由规则中通过data字段指定该路由所需的角色,让守卫可以动态获取权限要求:
const routes: Routes = [ { path: '', component: AuthComponent}, // 修正拼写错误:assitants → assistants { path: 'assistants', component: AssistantsComponent, canActivate: [AuthGuard], data: { roles: ['admin'] } // 仅允许admin角色访问 }, { path: 'client', component: ClientComponent, canActivate: [AuthGuard], data: { roles: ['client'] } // 仅允许client角色访问 } ];
二、改造AuthGuard,实现角色校验逻辑
在现有登录校验基础上,加入角色匹配逻辑。从token中解析用户角色后,与路由要求的角色对比:
import { Injectable } from '@angular/core'; import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router, UrlTree } from '@angular/router'; @Injectable({ providedIn: 'root' }) export class AuthGuard implements CanActivate { static readonly LOCAL_STORAGE_ACCESS_TOKEN = 'access_token'; // 注入Router用于页面跳转 constructor(private router: Router) {} canActivate( route: ActivatedRouteSnapshot, state: RouterStateSnapshot ): boolean | UrlTree { const accessToken = localStorage.getItem(AuthGuard.LOCAL_STORAGE_ACCESS_TOKEN); // 未登录则跳转至登录页 if (!accessToken) { return this.router.createUrlTree(['/']); } // 从JWT token中解析用户角色(根据你的token格式调整解析逻辑) const userRoles = this.parseRolesFromToken(accessToken); // 获取路由配置的必填角色 const requiredRoles = route.data['roles'] as string[]; // 校验角色权限 if (requiredRoles?.length) { const hasPermission = requiredRoles.some(role => userRoles.includes(role)); if (!hasPermission) { // 无权限时跳转至登录页或自定义403页面 return this.router.createUrlTree(['/']); } } return true; } private parseRolesFromToken(token: string): string[] { try { // JWT的payload是base64编码的第二部分 const payload = JSON.parse(atob(token.split('.')[1])); return payload.roles || []; } catch (err) { console.error('Token解析失败:', err); return []; } } }
三、通用化权限拆分(可选)
将登录校验和角色校验拆分为两个独立守卫,职责更单一,便于复用和扩展:
1. 单独实现RoleGuard
import { Injectable } from '@angular/core'; import { CanActivate, ActivatedRouteSnapshot, Router, UrlTree } from '@angular/router'; @Injectable({ providedIn: 'root' }) export class RoleGuard implements CanActivate { constructor(private router: Router) {} canActivate(route: ActivatedRouteSnapshot): boolean | UrlTree { const accessToken = localStorage.getItem(AuthGuard.LOCAL_STORAGE_ACCESS_TOKEN); const userRoles = this.parseRolesFromToken(accessToken!); const requiredRoles = route.data['roles'] as string[]; if (!requiredRoles.some(role => userRoles.includes(role))) { return this.router.createUrlTree(['/forbidden']); } return true; } private parseRolesFromToken(token: string): string[] { try { const payload = JSON.parse(atob(token.split('.')[1])); return payload.roles || []; } catch (err) { console.error('Token解析失败:', err); return []; } } }
2. 路由中组合使用守卫
const routes: Routes = [ { path: '', component: AuthComponent}, { path: 'assistants', component: AssistantsComponent, canActivate: [AuthGuard, RoleGuard], // 先校验登录状态,再校验角色权限 data: { roles: ['admin'] } }, { path: 'client', component: ClientComponent, canActivate: [AuthGuard, RoleGuard], data: { roles: ['client'] } } ];
这种拆分方式让每个守卫专注单一职责,后续新增权限规则时,只需调整RoleGuard或新增守卫即可。
内容的提问来源于stack exchange,提问作者Marek Vondra
相关产品推荐
相关产品推荐

