You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular14中如何实现基于角色的菜单与路由控制?

Angular14 基于角色的菜单实现方案

一、核心思路

先明确各角色对应的菜单权限(可根据实际需求调整):

  • Admin:Register、Login、Add New Employee、List of employees
  • Employee:Login、List of employees
  • Support:Login、List of employees、Add New Employee

通过登录后存储用户角色,在头部组件中根据角色动态过滤并渲染菜单,同时配合路由守卫防止无权限用户直接通过URL访问页面。

二、具体实现步骤

1. 完善用户认证服务(AuthService)

用响应式方式管理用户角色,确保菜单能实时更新:

// auth.service.ts
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';

@Injectable({ providedIn: 'root' })
export class AuthService {
  private currentUserRoleSubject = new BehaviorSubject<string | null>(null);
  currentUserRole$ = this.currentUserRoleSubject.asObservable();

  // 登录成功后存储角色
  setUserRole(role: string) {
    this.currentUserRoleSubject.next(role);
    localStorage.setItem('userRole', role); // 持久化存储
  }

  // 初始化时从本地存储读取角色
  initUserRole() {
    const role = localStorage.getItem('userRole');
    if (role) this.currentUserRoleSubject.next(role);
  }

  // 登出清除角色
  logout() {
    this.currentUserRoleSubject.next(null);
    localStorage.removeItem('userRole');
  }
}

2. 头部组件动态渲染菜单

在头部组件中订阅角色变化,过滤出当前角色可访问的菜单:

// header.component.ts
import { Component, OnInit } from '@angular/core';
import { AuthService } from '../services/auth.service';

interface MenuItem {
  label: string;
  route: string;
  allowedRoles: string[];
}

@Component({
  selector: 'app-header',
  templateUrl: './header.component.html',
  styleUrls: ['./header.component.css']
})
export class HeaderComponent implements OnInit {
  menuItems: MenuItem[] = [
    { label: 'Register', route: '/register', allowedRoles: ['Admin'] },
    { label: 'Login', route: '/login', allowedRoles: ['Admin', 'Employee', 'Support'] },
    { label: 'Add New Employee', route: '/add-employee', allowedRoles: ['Admin', 'Support'] },
    { label: 'List of employees', route: '/employees', allowedRoles: ['Admin', 'Employee', 'Support'] }
  ];

  filteredMenuItems: MenuItem[] = [];

  constructor(private authService: AuthService) {}

  ngOnInit(): void {
    this.authService.initUserRole();
    this.authService.currentUserRole$.subscribe(role => {
      if (!role) {
        // 未登录仅显示Login
        this.filteredMenuItems = this.menuItems.filter(item => item.label === 'Login');
        return;
      }
      this.filteredMenuItems = this.menuItems.filter(item => item.allowedRoles.includes(role));
    });
  }
}

头部组件模板:

<!-- header.component.html -->
<nav>
  <ul>
    <li *ngFor="let item of filteredMenuItems">
      <a [routerLink]="item.route">{{ item.label }}</a>
    </li>
    <li *ngIf="authService.currentUserRole$ | async">
      <button (click)="authService.logout()">Logout</button>
    </li>
  </ul>
</nav>

3. 路由守卫控制页面访问(可选但推荐)

防止用户直接通过URL访问无权限页面:

// role.guard.ts
import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router } from '@angular/router';
import { AuthService } from './auth.service';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';

@Injectable({ providedIn: 'root' })
export class RoleGuard implements CanActivate {
  constructor(private authService: AuthService, private router: Router) {}

  canActivate(
    route: ActivatedRouteSnapshot,
    state: RouterStateSnapshot
  ): Observable<boolean> {
    return this.authService.currentUserRole$.pipe(
      map(role => {
        const allowedRoles = route.data['allowedRoles'] as string[];
        if (!role) {
          this.router.navigate(['/login']);
          return false;
        }
        if (allowedRoles.includes(role)) return true;
        // 无权限跳转到首页或专属无权限页面
        this.router.navigate(['/']);
        return false;
      })
    );
  }
}

路由配置中使用守卫:

// app-routing.module.ts
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { RegisterComponent } from './register/register.component';
import { LoginComponent } from './login/login.component';
import { AddEmployeeComponent } from './add-employee/add-employee.component';
import { EmployeeListComponent } from './employee-list/employee-list.component';
import { RoleGuard } from './services/role.guard';

const routes: Routes = [
  { path: 'register', component: RegisterComponent, canActivate: [RoleGuard], data: { allowedRoles: ['Admin'] } },
  { path: 'login', component: LoginComponent },
  { path: 'add-employee', component: AddEmployeeComponent, canActivate: [RoleGuard], data: { allowedRoles: ['Admin', 'Support'] } },
  { path: 'employees', component: EmployeeListComponent, canActivate: [RoleGuard], data: { allowedRoles: ['Admin', 'Employee', 'Support'] } },
  { path: '', redirectTo: '/login', pathMatch: 'full' }
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule {}

三、注意事项

  • 优先使用currentUserRole$ Observable实现响应式菜单更新,确保角色变化时菜单实时刷新
  • 不能仅依赖前端菜单隐藏,必须配合路由守卫拦截非法访问
  • 若涉及敏感场景,建议后端返回用户角色信息,前端避免直接存储敏感数据,或使用HttpOnly Cookie管理登录状态

内容的提问来源于stack exchange,提问作者its me

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 18:55:30