我有一个包含这些表格的应用
user_id
用户外键)user_id
外键,向通道提供外channel_id
外)playlist_id
外键播放列表,而不使用user_id
外键) User
模型定义为:
public function channels()
{
return $this->hasMany('App\Channel');
}
Channel
模型定义为:
public function playlists()
{
return $this->hasMany('App\Playlist');
}
(和一个$this->belongsTo('App\User')
)
Playlist
模型定义为:
public function tracks()
{
return $this->hasMany('App\Track');
}
(和一个$this->belongsTo('App\Channel')
)
Track
模型定义为:
public function playlist()
{
return $this->belongsTo('App\Playlist');
}
现在在特定播放列表中列出曲目时,我会这样做:
function list($playlist) {
$tracks = Track::with('playlist')->get();
return response()->json($tracks);
}
这在页面http://.../tracks/2
(其中2是播放列表ID)上正常工作,但是如果用户将2更改为3,则他可能会看到播放列表#3中的曲目,而这可能不是他的。那么如何从播放列表中获取用户ID,以仅显示用户实际拥有的属于播放列表的曲目?
答案 0 :(得分:2)
在给定的代码中,您似乎并没有真正加载URL中ID所指定的播放列表。 $playlist
应为2
,其中包含示例网址(http://.../tracks/2
):
function list($playlist) {
$tracks = Track::with('playlist')->get();
return response()->json($tracks);
}
您只是在整个系统中加载 all 个曲目,并希望加载它们各自的Playlist
对象。
假设使用该URL,则要显示播放列表2的曲目,当且仅当该曲目属于经过身份验证的用户时,应该要做的是通过其ID查找播放列表,然后授权Playlist
属于登录用户,然后使用以下关系加载其tracks
:
public function list($id)
{
// Find a playlist with the given ID, or 404 if none could be found.
$playlist = Playlist::findOrFail($id);
// If the playlist does not belong to the user, throw an AuthorizationException.
if ($playlist->user_id != auth()->user()->id) {
throw new AuthorizationException();
}
// Return a response, passing through the tracks belonging to the playlist.
return response()->json($playlist->tracks);
}
处理授权的更好方法是使用Laravel's built in authorisation features,尤其是policies。这样一来,您就可以将授权逻辑与控制器分开,并将所有授权逻辑保留在相同/相似的位置:
php artisan make:policy PlaylistPolicy
创建策略,该策略将创建类App\Policies\PlaylistPolicy
。view
是我在此处建议的方法名称。该方法将接受2个参数,即经过身份验证的用户和您感兴趣的Playlist
对象:
public function view(User $user, Playlist $playlist)
{
//
}
在该方法中,您只需添加一些逻辑即可确定给定用户(登录用户)是否有权访问查看给定{{1} }。如果用户具有访问权限,则该方法应返回Playlist
,否则,将返回true
。
false
现在,您只需要在public function view(User $user, Playlist $playlist)
{
return $user->id === $playlist->user_id;
}
中注册策略。您只需将App\Providers\AuthServiceProvider
模型映射到Playlist
,只需添加到PlaylistPolicy
属性即可。
$policies
现在,可以使用protected $policies = [
Playlist::class => PlaylistPolicy::class
];
方法代替控制器中的if语句,该方法应该出现在控制器上(只要authorize
特征为{{1} } d)。
AuthorizesRequests