引言
认证(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 认证系统全家福:选哪个
- 2. 内置认证:Breeze、Fortify 与 Jetstream
- 3. API 认证:Sanctum 的两种模式
- 4. OAuth 2.0:Passport 与第三方接入
- 5. 授权系统:Gate、Policy 与中间件
- 6. RBAC 与 ABAC:从角色到属性
- 7. JWT 与 Session-less 认证
- 8. 多因子认证:MFA 工程实现
- 9. 安全最佳实践:常见攻击与防御
- 10. 速查表与一句话记忆
- 延伸阅读
1. Laravel 认证系统全家福:选哪个
1.1 四件套对比
| 方案 | 定位 | 认证方式 | 授权方式 | 学习成本 | 适用场景 |
|---|---|---|---|---|---|
| Laravel Breeze | 最基础 | Session + CSRF | 内置 | 低 | 小型项目、快速原型 |
| Laravel Fortify | 后端逻辑 | Session/API Token | 自定义 | 中 | 搭配前端框架(React/Vue) |
| Laravel Jetstream | 全栈方案 | Session + Sanctum | ABL 内置 | 高 | 中大型企业应用 |
| 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
| 维度 | Sanctum | JWT (tymon/jwt-auth) | Passport |
|---|---|---|---|
| 协议 | 自定义 Token | JWT (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 |
| XSS | Blade {{ }} 自动转义、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 Token | Bearer+能力 |
| Passport | OAuth 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-laravel-internals/ — Laravel 框架深入
- /php-api-design-rest/ — API 设计基础
- /php-security-hardening/ — PHP 安全专题
- Web 安全通用原则 — Web 安全общий
- Web 安全专题 — 安全通用原则
- 后端架构 — 认证授权在架构中的位置
- Laravel 官方文档
- OAuth 2.0 Simplified
- JWT.io — JWT 在线调试
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。