Laravel 认证与授权深度解析:Sanctum、Passport、Gate 与多因子

Laravel 认证与授权深度解析:内置认证系统(Breeze/Jetstream/Fortify/Jetstream 选择矩阵)、API 认证(Sanctum SPA/Token vs Passport OAuth)、授权系统(Gate 定义与闭包/Policy 类/中间件保护)、RBAC / ABAC 进阶ield 权限、JWT 与.session-less 认证、多因子认证(MFA)实现、安全最佳实践。

引言

认证(Authentication)证明「你是谁」,授权(Authorization)决定「你能做什么」。二者合称 AuthN 与 AuthZ,是后端安全体系中最关键的两扇门。Laravel 的 Auth 子系统以「开箱即用」著称——auth()->user() 随手可取。但生产环境的认证远不止「登录成功」:API 无状态 Token、OAuth 第三方接入、页面级与资源级的细粒度授权、多因子的安全加固。本文从 Laravel 内置系统延伸到 Sanctum/Passport、Gate/Policy、RBAC 与 MFA,构建一份完整的企业级认证授权决策图谱。

前置:/php-laravel-internals/(框架深入)、/php-api-design-rest/(API 设计基础)。


目录


1. Laravel 认证系统全家福:选哪个

1.1 四件套对比

方案定位认证方式授权方式学习成本适用场景
Laravel Breeze最基础Session + CSRF内置低小型项目、快速原型
Laravel Fortify后端逻辑Session/API Token自定义中搭配前端框架(React/Vue)
Laravel Jetstream全栈方案Session + SanctumABL 内置高中大型企业应用
Sanctum(单独)API & SPA 认证Token / SPA Cookie自定义低API 独立服务、前后端分离

1.2 关键概念速览

AuthN(认证):证明你是你(密码/Token/OAuth/MFA)
AuthZ(授权):决定你能做什么(Gate/Policy/RBAC)
Session:服务器端有状态(默认 Breeze/Jetstream)
Token:服务器端无状态(API 首选)

记忆:Laravel 四件套按场景选——Breeze 小项目、Fortify 配自定义前端、Jetstream 全栈企业级、Sanctum 独立 API;认证=证明身份、授权=决定权限、Session=后端有状态、Token=无状态。


2. 内置认证:Breeze、Fortify 与 Jetstream

2.1 Breeze(快速原型)

# 安装
composer require laravel/breeze --dev
php artisan breeze:install
npm install && npm run build

# 提供:注册、登录、邮箱验证、密码重置
# 纯 Blade + Alpine.js,无额外依赖
# 生产环境:建议从 Breeze 开始,逐步替换为自定义

2.2 Fortify(后端逻辑分离)

# 纯后端:提供 Auth 服务而不绑定视图
# 典型用法:前后端分离,前端 React/Vue 调用 Fortify API
# 需要手动注册路由和构建前端页面

2.3 Jetstream(全栈企业级)

# 团队/多团队、API Token 管理、Two-Factor Auth
# 支持 Livewire 或 Inertia.js 前端
# "大而全"的代价:模板重、自定义成本不低

2.4 选择策略

小项目(< 50 用户):Breeze
中等项目(前后端分离):Fortify + Sanctum + 自定义前端
大型企业(多团队、2FA、API):Jetstream(或自研基于 Fortify)

记忆:Breeze 极简(Blade+Alpine)、Fortify 分离前后端逻辑(React/Vue 搭档)、Jetstream 全功能(团队+2FA+API+Livewire)——选型看规模与是否前后端分离。


3. API 认证:Sanctum 的两种模式

3.1 SPA 认证模式(Cookie)

# 前后端同源(或同域名子域名)时,用 Sanctum 的 SPA 认证
# 配置:config/sanctum.php 添加 SPA 域名
# 前端携带 withCredentials + CSRF token
# 后端通过 web guard 的 session 认证用户
# 无 Token 开销,依赖同源策略 = 适合 SSR 或同域部署

API 路由:
Route::middleware(['auth:sanctum'])->get('/user', fn() => auth()->user());

3.2 Token 认证模式

# 创建 Token
$token = $user->createToken('api-token', ['read', 'write'])->plainTextToken;

# 请求携带
Authorization: Bearer {token}

# Token 能力(Abilities)
$user->tokens()->delete();                      # 撤销全部
$user->tokens()->where('name', 'web')->delete(); # 撤销指定

3.3 Sanctum vs JWT vs Passport

维度SanctumJWT (tymon/jwt-auth)Passport
协议自定义 TokenJWT (RFC 7519)OAuth 2.0
状态无状态无状态(Token 含声明)有状态(DB 存 Token)
Token 过期手动管理exp 字段自过期刷新 Token 自动更新
适用SPA/移动/简单 API微服务间认证第三方 OAuth 接入

记忆:Sanctum 两模式——SPA(同域 Cookie+CSRF)和 Token(Bearer 能力细控);比 JWT 更 Laravel 原生、Passport 更轻量;SPA 模式无 Token 开销,Token 模式支持多客户端与能力粒控。


4. OAuth 2.0:Passport 与第三方接入

4.1 何时用 Passport

# 允许多平台接入(客户端 App、第三方 Web 服务)
# 标准的 OAuth 2.0 流程:授权码/客户端凭证/密码/隐式授权
# 支持 Personal Access Token(内部服务间通信)
# 比 Sanctum 重:需要管理客户端、Token、Scope
composer require laravel/passport
php artisan passport:install

4.2 OAuth 2.0 授权码流程

1) 用户点击「用 X 登录」(302 到授权服务)
2) 用户确认授权,返回授权码(code)
3) 后端用 code + client_secret 换 access_token + refresh_token
4) 用 access_token 调用用户资源 API

4.3 Laravel Socialite:第三方快速接入

# 一行接入 GitHub/Google/Facebook
composer require laravel/socialite

# 配置(config/services.php)后:
Route::get('/auth/github/redirect', [AuthController::class, 'redirect']);
Route::get('/auth/github/callback', [AuthController::class, 'callback']);

# 典型回调逻辑:取用户信息 → 查找/创建本地用户 → 登录
$user = Socialite::driver('github')->user();

记忆:Passport 给需要多平台 OAuth 接入的场景(客户端/第三方/Scope 管控),Socialite 一行式接入 GitHub/Google/Twitter;授权码流程是比隐式更安全的标准做法。


5. 授权系统:Gate、Policy 与中间件

5.1 Gate(简单权限判断)

// AuthServiceProvider::boot()
Gate::define('edit-post', function (User $user, Post $post) {
    return $user->id === $post->user_id;
});

// 控制器中
if (Gate::allows('edit-post', $post)) { ... }
// Blade 中
@can('edit-post', $post) ... @endcan

5.2 Policy(面向资源)

// php artisan make:policy PostPolicy --model=Post
class PostPolicy {
    public function update(User $user, Post $post): bool {
        return $user->id === $post->user_id;
    }
}

// 控制器 + 隐式绑定
public function update(Post $post) {
    $this->authorize('update', $post);  // 未授权抛 403
}

5.3 中间件一次性保护路由

Route::middleware(['can:update,post'])->put('/posts/{post}', ...);
Route::middleware(['can:delete,post'])->delete('/posts/{post}', ...);

5.4 Gate vs Policy 速查

场景选择原因
简单布尔判断(如"是否管理员")Gate一行搞定
围绕一个 Eloquent 模型的权限Policy与模型绑定,代码组织清晰
用户隔离(只能改自己的数据)Policy + 隐式绑定自动化,每动作一行

记忆:Gate 做简单布尔判断(一行定义)、Policy 围绕 Eloquent 模型(每项动作一个方法)、中间件 can 做路由级保护;Blade 用 @can/@cannot 做视图层控制——按场景选工具。


6. RBAC 与 ABAC:从角色到属性

6.1 Spatie Laravel-permission(RBAC)

composer require spatie/laravel-permission

# 角色(Role)= 一组权限(Permission)的集合
$user->assignRole('editor');
$user->givePermissionTo('edit posts');

# 中间件
Route::middleware(['role:admin'])->get('/admin', ...);
Route::middleware(['permission:publish posts'])->post('/posts', ...);

6.2 数据库表结构

roles: id, name, guard_name
permissions: id, name, guard_name
model_has_roles: role_id, model_type, model_id
model_has_permissions: permission_id, model_type, model_id
role_has_permissions: permission_id, role_id

6.3 ABAC(基于属性)

# RBAC:"你是 admin 就能操作"
# ABAC:"你是 admin 且文章在草稿状态 且 工作时间 才能发布"
# 实现:Gate 闭包里写多条件判断,或结合 Policy
Gate::define('publish-post', function ($user, $post) {
    return $user->hasRole('editor')
        && $post->status === 'draft'
        && now()->isWeekday();
});

记忆:RBAC 用 Spatie 包实现「角色=权限集合」快速上手;ABAC 在 RBAC 之上加条件判断(时间/状态/上下文),用 Gate 闭包或 Policy 多条件实现——越细粒度越靠近 ABAC。


7. JWT 与 Session-less 认证

7.1 JWT 原理

结构:Header.Payload.Signature
Header: 算法(HS256/RS256)
Payload: sub(用户ID)、iat(签发时间)、exp(过期时间)、自定义声明
Signature: 签名 = HMAC(Header + Payload, Secret)
# Token 自包含:服务器拿到就能验签+解码,无需 DB 查询

7.2 Laravel 中集成 JWT

composer require tymon/jwt-auth

# 配置后:
$credentials = request(['email', 'password']);
if (! $token = auth('api')->attempt($credentials)) {
    return response()->json(['error' => 'Unauthorized'], 401);
}
return response()->json(compact('token'));

7.3 JWT 利弊

优点缺点
无状态,服务横向扩展友好Token 过期前无法吊销(除非黑名单)
跨域天然友好Payload 暴露(只签不加密)
声明自包含,减少 DB 查询Token 长度比 Session ID 大

7.4 吊销策略

# Token 黑名单(Redis)
Redis::setex('blacklist:' . $jti, $ttl, 1);

# 配合 exp 和 refresh token:
# access_token 短活(15 min)、refresh_token 长活(7 天)
# refresh 时检查是否在黑名单 + 是否在「Token 家族」白名单

记忆:JWT = Header.Payload.Signature 三段自包含结构,无状态可横向扩展,但「过期前无法吊销」是硬伤,用 Redis 黑名单或短活 access_token + 长活 refresh_token 缓解。


8. 多因子认证:MFA 工程实现

8.1 因子分类

知识因子:密码、PIN
持有因子:手机/硬件密钥
生物因子:指纹、面部识别

8.2 Laravel 中实现 TOTP(Jetstream 内置)

# Jetstream 启用 twoFactorAuthentication
# 用户启用后需扫码绑定 Authenticator App(Google/Microsoft)
# 登录时第二步输入 6 位 TOTP 码
# 原理:基于共享密钥 + 时间窗口(30s)生成一次性码

8.3 自研 MFA 流程

1) 正常登录(邮箱+密码)→ 第一步通过
2) 生成临时 Token(15 min 有效)
3) 发送 SMS/邮件含一次性码,或要求 TOTP
4) 验证一次性码 → 签发正式 Session/Token
5) 设备指纹记住:下次同设备可跳过 MFA
# 设备指纹:User-Agent + IP 段 + 浏览器指纹哈希

8.4 安全注意事项

# SMS 不安全:SIM 交换攻击、社工获取
# TOTP 比 SMS 安全(但密钥泄露=可重放)
# FIDO2/WebAuthn 最强:物理密钥,防钓鱼

记忆:MFA 三类因子——知识(密码)、持有(手机)、生物(指纹);TOTP 基于时间窗口+共享密钥;流程=先登录→发一次性码→验→签发正式 Token;SMS 最弱、FIDO2/WebAuthn 最强。


9. 安全最佳实践:常见攻击与防御

9.1 攻击矩阵

攻击防御
暴力破解登录速率限制(5 次/分钟)、验证码
CSRF所有非 GET 请求 CSRF Token + SameSite Cookie
XSSBlade {{ }} 自动转义、CSP 头
会话固定登录后 session()->regenerate()
密码泄露bcrypt 哈希(Laravel 自动)、密码强度检查
Token 泄露HTTPS only、HttpOnly Cookie、Token 短活

9.2 SQL 注入与 Auth

# Laravel 的 Eloquent/Query Builder 自动参数绑定,避免 SQL 注入
# 但手写 DB::raw() 和 raw where 时仍可能漏
User::whereRaw("email = '$email'")     # 危险!
User::where('email', $email)           # 安全(参数绑定)

9.3 审计日志

# 记录关键操作:登录/登出/密码修改/授权变更
# Laravel 事件监听:Login/Logout/PasswordReset
Event::listen(Login::class, function ($event) {
    AuditLog::create([
        'user_id' => $event->user->id,
        'action' => 'login',
        'ip' => request()->ip(),
        'user_agent' => request()->userAgent(),
    ]);
});

记忆:安全五件套——速率限暴力、CSRF Token 护非 GET、XSS 靠 Blade 自动转义+CSP、会话固定靠 regenerate、密码泄露靠 bcrypt;SQL 注入用 Eloquent 参数绑定不用 raw;关键操作记审计日志。


10. 速查表与一句话记忆

概念一句话
Breeze小型项目原型
Fortify前后端分离
Jetstream企业全栈
Sanctum SPA同域 Cookie
Sanctum TokenBearer+能力
PassportOAuth 2.0 多平台
Socialite一行第三方登录
Gate简单布尔权限
Policy资源级权限
RBAC角色=权限集合
ABAC属性条件权限
JWT无状态自包含 Token
MFA知识+持有+生物
TOTP时间窗口一次性码
FIDO2物理密钥防钓鱼

一句话记忆:Laravel 认证授权体系按规模选型——Breeze 原型、Fortify 前后端分离、Jetstream 企业全栈;API 认证 Sanctum(SPA Cookie 或 Bearer Token)、第三方 OAuth 用 Passport、一行接入用 Socialite;授权用 Gate(简单布尔)、Policy(资源级)、RBAC(Spatie 角色集合)、ABAC(属性条件);JWT 无状态但无法吊销→Redis 黑名单或短活 access+长活 refresh 缓解;MFA 三因子——知识/持有/生物,TOTP 时间窗口是通用方案,FIDO2 最强;安全五件套——速率限/CSRF/转义/regenerate/bcrypt,关键操作记审计日志——「认证认准身份、授权锁住权限、多层因子+审计是安全的底线」。


延伸阅读

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页

「php」更多文章

  1. Laravel 事件广播:实时通知、WebSocket 与队列驱动架构
  2. PHP 数据库迁移治理:架构设计、版本控制与多环境管理
  3. WordPress 开发实战:主题定制、插件架构与 Headless CMS