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

Laravel Policy与Show方法权限控制问题:用户数据隔离验证

Laravel Policy 权限验证问题:按关联Objekt过滤ObjektVerwaltung数据

我用Laravel Policy做数据权限控制,所有表都有user_id字段,通过对比当前登录用户ID和数据的user_id实现验证。现在有Objekt和ObjektVerwaltung两张表,通过objekt_id外键关联,需要确保用户只能查看和自己有权限的Objekt关联的ObjektVerwaltung数据。


现有代码

ObjektVerwaltung控制器的show方法

public function show($objektvwId) {
    $objektId = ObjektVerwaltung::with('Objekt')->find($objektvwId);
    
    $this->authorize('view', $objektId);
    $objekte = ObjektVerwaltung::where('objekt_id',$objektvwId)->get();
  
    return view('objekte.verwaltung', compact('objekte'));
}

Policy代码

public function view(User $user, ObjektVerwaltung $objektVerwaltung)
{
    return $objektVerwaltung->user_id === $user->id;
}

模型代码

ObjektVerwaltung模型

class ObjektVerwaltung extends Model
{
    use HasFactory;

    protected $table = 'objekte_verwaltungens';

    protected $fillable = ['user_id','objekt_id','key', 'value'];

    public function Objekt() {
        return $this->belongsTo(Objekt::class);
    }
}

Objekt模型

class Objekt extends Model
{
    use HasFactory;

    protected $table = 'objekts';

    protected $fillable = ['name','strasse', 'hausnummer', 'plz', 'ort', 'user_id'];

    public function Mieter() {
        return $this->hasMany(Mieter::class);
    }

    public function Company() {
        return $this->belongTo(Company::class);
    }

    public function Objektverwaltung() {
        return $this->hasMany(ObjektVerwaltung::class);
    }
}

遇到的问题

我知道用find()可以验证单条数据,但现在需要按objekt_id过滤一组ObjektVerwaltung数据,没法直接用find()。尝试用where()查询后调用authorize(),一直触发Unauthorized,甚至无法进入Policy逻辑。比如这段代码:

$objekt= ObjektVerwaltung::where('objekt_id', $objektId)->get();        
$this->authorize('view', $objekt); 

请求解决这个权限验证的问题。


解决方案

1. 修正Policy逻辑,关联验证Objekt的user_id

当前Policy只验证ObjektVerwaltung自身的user_id,但需求是验证关联的Objekt是否属于当前用户,调整Policy:

public function view(User $user, ObjektVerwaltung $objektVerwaltung)
{
    // 验证关联的Objekt归属当前用户
    return $objektVerwaltung->Objekt->user_id === $user->id;
}

注意:为避免N+1查询,控制器查询时要提前预加载关联的Objekt:ObjektVerwaltung::with('Objekt')->find($objektvwId);

2. 批量数据的权限验证:用viewAny方法或直接过滤

如果要验证一组ObjektVerwaltung数据(比如按objekt_id查询的集合),有两种可行方式:

方式一:定义viewAny方法

在ObjektVerwaltungPolicy中添加批量验证方法:

public function viewAny(User $user, $objektId)
{
    // 先验证当前用户拥有该Objekt的权限
    $objekt = Objekt::findOrFail($objektId);
    return $objekt->user_id === $user->id;
}

控制器调用时传入Objekt模型类和objekt_id:

public function show($objektId) {
    $this->authorize('viewAny', [ObjektVerwaltung::class, $objektId]);
    
    // 查询该Objekt下的所有Verwaltung数据
    $objekte = ObjektVerwaltung::where('objekt_id', $objektId)->get();
  
    return view('objekte.verwaltung', compact('objekte'));
}

方式二:直接在查询时过滤用户权限

更简洁的方式是通过双重条件查询确保数据安全,无需额外修改Policy:

public function show($objektId) {
    // 先确认Objekt属于当前用户,不存在则抛出404
    $objekt = Objekt::where('id', $objektId)->where('user_id', auth()->id())->firstOrFail();
    
    // 通过关联关系查询该Objekt下的所有Verwaltung数据
    $objekte = $objekt->Objektverwaltung()->get();
  
    return view('objekte.verwaltung', compact('objekte'));
}

3. 修正控制器变量命名错误

原控制器中$objektId = ObjektVerwaltung::with('Objekt')->find($objektvwId);变量名混淆,$objektId实际是ObjektVerwaltung实例,应改为:

public function show($objektvwId) {
    $objektVerwaltung = ObjektVerwaltung::with('Objekt')->findOrFail($objektvwId);
    
    $this->authorize('view', $objektVerwaltung);
    // 通过关联获取该Objekt下的所有Verwaltung数据
    $objekte = $objektVerwaltung->Objekt->Objektverwaltung;
  
    return view('objekte.verwaltung', compact('objekte'));
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 01:10:29