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

如何在Angular中创建访客Guard,配合Laravel Sanctum实现认证控制

解决方案:Laravel Sanctum + Angular 访客与登录用户权限区分

一、后端Laravel配置(处理访客令牌)

因为你的API受auth:sanctum保护,访客需要合法令牌才能访问问题列表接口,这里通过「固定访客用户」生成令牌的方式实现:

  1. 创建访客用户
    先在数据库中添加标记为访客的用户,可通过Seeder实现:
// database/seeders/GuestUserSeeder.php
<?php

namespace Database\Seeders;

use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
use App\Models\User;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Str;

class GuestUserSeeder extends Seeder
{
    public function run()
    {
        User::firstOrCreate(
            ['email' => 'guest@example.com'],
            [
                'name' => '匿名访客',
                'password' => Hash::make(Str::random(32)), // 随机密码,无需访客知晓
                'is_guest' => true, // 需先在users表添加is_guest字段(boolean类型)
            ]
        );
    }
}

执行Seeder:php artisan db:seed --class=GuestUserSeeder

  1. 新增访客令牌接口
    开放无需认证的接口,供前端获取访客令牌:
// routes/api.php
Route::post('/guest/token', function () {
    $guestUser = \App\Models\User::where('is_guest', true)->first();
    $token = $guestUser->createToken('Anonymous Guest Token')->plainTextToken;
    return response()->json(['token' => $token]);
});
  1. API路由权限控制
    保持问题列表接口受auth:sanctum保护,创建问题接口额外拦截访客:
Route::middleware('auth:sanctum')->group(function () {
    // 访客和登录用户都能访问的问题列表
    Route::get('/questions', [\App\Http\Controllers\QuestionController::class, 'index']);
    // 仅登录用户能访问的创建问题接口
    Route::post('/questions', [\App\Http\Controllers\QuestionController::class, 'store'])
        ->middleware(function ($request, $next) {
            if ($request->user()->is_guest) {
                return response()->json(['message' => '访客无法创建问题'], 403);
            }
            return $next($request);
        });
});

二、前端Angular配置(路由守卫与令牌管理)

基于你已有的登录用户AuthGuard,新增访客守卫并完善令牌逻辑:

  1. 创建访客守卫GuestGuard
    拦截访客访问创建问题页面,仅允许登录用户进入:
// src/app/guards/guest.guard.ts
import { Injectable } from '@angular/core';
import { CanActivate, Router } from '@angular/router';
import { AuthService } from '../services/auth.service';

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

  canActivate(): boolean {
    // 已登录用户允许访问,访客直接跳首页
    if (this.authService.isAuthenticatedUser()) {
      return true;
    }
    this.router.navigate(['/']);
    return false;
  }
}
  1. 完善AuthService管理令牌与用户状态
    区分登录用户和访客,自动获取访客令牌:
// src/app/services/auth.service.ts
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { BehaviorSubject, Observable } from 'rxjs';

@Injectable({ providedIn: 'root' })
export class AuthService {
  private currentUser$ = new BehaviorSubject<any>(null);

  constructor(private http: HttpClient) {
    this.initAuthState();
  }

  private initAuthState(): void {
    const token = localStorage.getItem('auth_token');
    const user = localStorage.getItem('user_info');

    if (user) {
      this.currentUser$.next(JSON.parse(user));
    } else if (token) {
      // 只有令牌,判定为访客
      this.currentUser$.next({ isGuest: true });
    } else {
      // 无令牌,自动获取访客令牌
      this.fetchGuestToken();
    }
  }

  fetchGuestToken(): void {
    this.http.post('/api/guest/token', {}).subscribe((res: any) => {
      localStorage.setItem('auth_token', res.token);
      this.currentUser$.next({ isGuest: true });
    });
  }

  // 判断是否为登录用户(非访客)
  isAuthenticatedUser(): boolean {
    const user = this.currentUser$.value;
    return user && !user.isGuest;
  }

  // 登录逻辑:覆盖访客令牌,存储登录用户信息
  login(email: string, password: string): Observable<any> {
    return this.http.post('/api/login', { email, password });
  }

  handleLoginResponse(res: any): void {
    localStorage.setItem('auth_token', res.token);
    localStorage.setItem('user_info', JSON.stringify(res.user));
    this.currentUser$.next(res.user);
  }

  // 登出逻辑:清除登录信息,重新获取访客令牌
  logout(): void {
    localStorage.removeItem('auth_token');
    localStorage.removeItem('user_info');
    this.fetchGuestToken();
  }
}
  1. 路由配置
    给创建问题页面绑定GuestGuard,首页无守卫:
// src/app/app-routing.module.ts
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { HomeComponent } from './home/home.component';
import { CreateQuestionComponent } from './create-question/create-question.component';
import { AuthGuard } from './guards/auth.guard';
import { GuestGuard } from './guards/guest.guard';

const routes: Routes = [
  { path: '', component: HomeComponent },
  // 仅登录用户可访问创建页面
  { path: 'create', component: CreateQuestionComponent, canActivate: [GuestGuard] },
  // 其他登录用户专属路由用你已有的AuthGuard
  { path: 'profile', component: ProfileComponent, canActivate: [AuthGuard] },
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }
  1. API请求拦截器
    自动给所有API请求带上令牌:
// src/app/interceptors/auth.interceptor.ts
import { Injectable } from '@angular/core';
import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent } from '@angular/common/http';
import { Observable } from 'rxjs';

@Injectable()
export class AuthInterceptor implements HttpInterceptor {
  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    const token = localStorage.getItem('auth_token');
    if (token) {
      req = req.clone({
        setHeaders: {
          Authorization: `Bearer ${token}`
        }
      });
    }
    return next.handle(req);
  }
}

在AppModule中注册拦截器:

// src/app/app.module.ts
import { HTTP_INTERCEPTORS } from '@angular/common/http';
import { AuthInterceptor } from './interceptors/auth.interceptor';

@NgModule({
  providers: [
    { provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true }
  ]
})
export class AppModule { }

三、验证逻辑说明

  • 访客打开页面时,前端自动请求访客令牌并存储,后续API请求带上该令牌,后端识别为访客用户,允许访问问题列表但拒绝创建操作;
  • 登录用户登录后,前端存储登录令牌和用户信息,覆盖访客令牌,此时GuestGuard会允许其访问创建页面,后端也会识别为非访客用户,允许创建操作;
  • 登出后,前端清除登录信息,重新获取访客令牌,回到访客状态。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 05:03:37