@auth和@guest默认仅检查默认guard(如web)的登录状态,不校验角色权限;多guard需显式指定如@auth('admin');自定义指令如@authrole应封装可测逻辑,避免模板中嵌套复杂判断或滥用@can。

Blade 中 @auth 和 @guest 默认行为是什么
默认的 @auth 只检查当前用户是否已通过 Laravel 的 Auth::check(),不关心角色、权限或 guard 类型。它等价于 @if(Auth::check()),底层用的是默认 guard(通常是 web)。如果你项目里用了多个 guard(比如 admin 或 api),直接写 @auth 会走错通道,返回意外的 false。
常见错误现象:@auth 在后台路由里始终不生效,但 Auth::guard('admin')->check() 明明返回 true —— 就是因为指令没指定 guard。
- 必须显式传 guard 名:
@auth('admin') - 对应闭合用
@endauth,不能混用@else或@guest嵌套(Laravel 9+ 允许@auth('x') @else @guest('x'),但语义易乱,不推荐) -
@guest同理,默认也是webguard,要写成@guest('admin')才匹配
如何自定义 @auth 指令实现角色/权限判断
Laravel 不允许直接覆盖内置 @auth,但可以注册新指令,比如 @role、@can(后者其实已内置),或更语义化的 @authRole。关键不是“改指令”,而是把逻辑收口到一个可复用、易测试的辅助函数里。
使用场景:管理员后台需要 @authRole('super_admin'),而普通用户页用 @authRole('member'),避免模板里散落 Auth::user()->hasRole(...)。
- 在
App\Providers\AppServiceProvider::boot()里注册:Blade::if('authRole', function (string $role) { return Auth::check() && Auth::user()->hasRole($role); }); - 注意:这个闭包里不能用
$this,也不能依赖 request 或 session 以外的状态;如果hasRole()是基于数据库查的,高频页面可能触发 N+1,建议提前 eager load 或加缓存 - 参数差异:
@authRole('admin')是字符串,@authRole(['editor', 'publisher'])需要改闭包支持数组,否则报错Argument 1 passed to ... must be of the type string
@auth 和 @can 混用时的坑
很多人以为 @auth @can('delete', $post) 是安全的两层校验,其实只要 @auth 成立,@can 就会执行;但如果用户未登录,@can 里的 $post 可能是 null,导致 Policy 构造函数或 before() 方法抛出 Trying to get property 'id' of null。
性能影响:每次 @can 都会实例化对应 Policy,并调用 before() + 具体方法;如果 Policy 里有 DB 查询或外部 API 调用,模板里多几个 @can 就容易拖慢首屏。
- 务必先判空:
@auth @if($post) @can('delete', $post) ... @endcan @endif @endauth - 不要在循环里滥用:
@foreach($posts as $post) @can('view', $post) ... @endcan @endforeach→ 改用withCount('permissions')或预加载策略结果 -
@can底层走的是Gate::inspect(),它不短路:即使before()返回 deny,也会继续执行具体方法,所以before()里别做重操作
为什么别在 Blade 里写复杂条件逻辑
比如把 @auth('api') && Auth::user()->is_active && in_array(Auth::user()->type, ['trial', 'paid']) 直接塞进指令里,看着省事,实际带来三个问题:无法单元测试、IDE 无提示、上线后改规则要翻遍所有模板。
容易被忽略的地方:Blade 编译后的 PHP 文件缓存在 storage/framework/views/,修改指令逻辑后,如果没清缓存,旧行为还会残留——尤其部署到线上时,常被当成“玄学 bug”。
- 把判断逻辑提到 ViewModel 或 Presenter 类里,比如
UserAccess::canSeeDashboard(Auth::user()) - 在控制器里算好布尔值传给视图:
'can_edit_profile' => $user->can('update', Profile::class) - 清 view 缓存命令是
php artisan view:clear,CI/CD 流程里记得加上











