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

Angular+Laravel开发:如何在前端存储权限以控制菜单显示?

在Angular SPA中结合Laravel Sanctum与Spatie Permissions实现权限控制

1. 后端调整:登录接口返回用户权限/角色

在Laravel登录逻辑中,验证用户成功后,将用户的权限(或角色)一并返回给前端。基于Spatie Permissions可以这样实现:

// 登录控制器示例代码
public function login(Request $request)
{
    if (!Auth::attempt($request->only('email', 'password'))) {
        return response()->json(['message' => 'Invalid credentials'], 401);
    }

    $user = Auth::user();
    // 获取用户所有权限(Spatie内置方法)
    $permissions = $user->getAllPermissions()->pluck('name')->toArray();
    // 也可以获取用户所属角色
    $roles = $user->getRoleNames()->toArray();

    return response()->json([
        'token' => $user->createToken('auth_token')->plainTextToken,
        'permissions' => $permissions,
        'roles' => $roles
    ]);
}

2. 前端修改AuthService:存储权限并添加判断方法

更新你的Angular AuthService,在登录时同步存储权限信息,并封装权限检查方法:

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { Router } from '@angular/router';

@Injectable({
  providedIn: 'root'
})
export class AuthService {

  private baseURL = "http://localhost:8000/api";

  constructor(private http: HttpClient, public router: Router) { }

  login(username: string, password: string): Observable<boolean> {
    return this.http.post<{token: string, permissions: string[], roles: string[]}>(this.baseURL+'/login', {email: username, password: password})
      .pipe(
        map(result => {
          localStorage.setItem('access_token', result.token);
          // 将权限和角色转为JSON字符串存储到localStorage
          localStorage.setItem('user_permissions', JSON.stringify(result.permissions));
          localStorage.setItem('user_roles', JSON.stringify(result.roles));
          return true;
        })
      );
  }

  getToken() {
    return localStorage.getItem('access_token');
  }

  // 获取用户权限列表
  getPermissions(): string[] {
    const permissions = localStorage.getItem('user_permissions');
    return permissions ? JSON.parse(permissions) : [];
  }

  // 获取用户角色列表
  getRoles(): string[] {
    const roles = localStorage.getItem('user_roles');
    return roles ? JSON.parse(roles) : [];
  }

  // 检查是否拥有指定权限
  hasPermission(permission: string): boolean {
    return this.getPermissions().includes(permission);
  }

  // 检查是否拥有指定角色
  hasRole(role: string): boolean {
    return this.getRoles().includes(role);
  }

  logout() {
    // 清除所有认证相关存储
    localStorage.removeItem('access_token');
    localStorage.removeItem('user_permissions');
    localStorage.removeItem('user_roles');
    this.router.navigate(['login']);
  }

  public get isLoggedIn(): boolean {
    // 建议补充token过期校验,比如解析JWT判断有效期
    return localStorage.getItem('access_token') !== null;
  }
}

3. 前端控制菜单显示

在菜单组件中,使用*ngIf结合AuthService的方法来控制菜单的显示隐藏:

<!-- 侧边栏菜单示例 -->
<ul class="sidebar-menu">
  <li *ngIf="authService.isLoggedIn">
    <a routerLink="/dashboard">控制台</a>
  </li>
  <!-- 仅拥有manage_users权限的用户可见 -->
  <li *ngIf="authService.hasPermission('manage_users')">
    <a routerLink="/users">用户管理</a>
  </li>
  <!-- 仅admin角色的用户可见 -->
  <li *ngIf="authService.hasRole('admin')">
    <a routerLink="/settings">系统设置</a>
  </li>
</ul>

记得在组件中注入AuthService:

import { AuthService } from '../services/auth.service';

@Component({
  selector: 'app-sidebar',
  templateUrl: './sidebar.component.html'
})
export class SidebarComponent {
  constructor(public authService: AuthService) {}
}

4. 关键注意事项

  • 前端控制仅为UI层面:绝对不能依赖前端权限控制保护API接口,后端必须在每个需要授权的接口中使用Spatie Permissions中间件或Laravel Gates做校验,示例:
    // 路由示例
    Route::get('/users', [UserController::class, 'index'])->middleware('permission:manage_users');
    
  • 权限更新同步:如果后端用户权限发生变化,前端需要重新获取最新权限(比如用户重新登录,或提供专门的刷新权限接口)。
  • 存储安全性:若担心localStorage的风险,可改用sessionStorage,或结合Angular服务变量+路由守卫,但后者刷新页面后会丢失权限数据,建议搭配localStorage使用同时确保全站HTTPS传输。

内容的提问来源于stack exchange,提问作者Kennedy Mwenda

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 19:24:10