Laravel Nova 授权
当访问 Nova 的用户只有你和你或者公司内部的开发团队时,Nova 接收请求之前你是不需要添加额外的授权的。然而,如果你想要提供给客户或者大型开发团队去访问你的客户端时,你可能希望对某些请求加上权限。例如,只希望管理员可以删除记录。值得高兴的是,Nova 提供了一种简单的授权方法,这种方法正如你所了解的 Laravel 中的许多功能一样。
策略
为了限制用户的哪些用户可以查看、创建、更新、或者删除资源,Nova 利用了 Laravel 授权策略,策略是一个用于管理特定模型或者资源授权逻辑的简单类。例如,如果你的程序是一个博客,你可能有一个 Post
模型和相应的
PostPolicy
在你的程序中。
在 Nova 中操作资源时, Nova 会自动的尝试为模型找相应的策略。通常,这些策略会在你应用程序的 AuthServiceProvider
中注册。如果 Nova 监测到你已经为模型注册了策略,他将在执行各自的操作前,自动检查该策略的相关授权方法,例如:
viewAny
view
create
update
delete
restore
forceDelete
不需要额外的配置!例如,要确定允许哪些用户能够更新 Post
模型,你只需在相应的策略类上定义一个 update
方法:
<?php
namespace App\Policies;
use App\User;
use App\Post;
use Illuminate\Auth\Access\HandlesAuthorization;
class PostPolicy
{
use HandlesAuthorization;
/**
* 检查用户是否能够更新帖子模型
*
* @param \App\User $user
* @param \App\Post $post
* @return mixed
*/
public function update(User $user, Post $post)
{
return $user->type == 'editor';
}
}
未定义策略方法
如果策略存在但缺少特定的操作方法的策略,所有用户将不会被允许执行相应的操作的,所以,当你已经定义策略后,请定义其所有的相关授权方法。
隐藏实体资源
如果你希望对你的用户隐藏一个 Nove 的实体资源,你可以定义一个 viewAny
方法在对应模型的策略类上。如果在该模型的策略类上没有 viewAny
方法,Nova 认为所有用户都能查看该资源:
<?php
namespace App\Policies;
use App\User;
use App\Post;
use Illuminate\Auth\Access\HandlesAuthorization;
class PostPolicy
{
use HandlesAuthorization;
/**
* 确定用户是否可以查看任何帖子
*
* @param \App\User $user
* @return mixed
*/
public function viewAny(User $user)
{
return in_array('view-posts', $user->permissions);
}
}
模型关系
我们已经学会了怎样授权简单的视图、创建、更新和删除动作,但是模型关系的交互呢?例如,如果你希望建立一个播客程序,你希望某些特定的 Nova 用户可以给播客评论。同样的,Nova 使用了 Laravel 的策略简单的实现。
使用模型关系时,Nova 使用了简单的命名规则。为了简单的说明这个规则,让我们假设你的程序具有 Podcast
资源和 Comment
资源。如果你希望某个授权的用户能够给一篇播客添加评论,你应该在播客模型的策略类里定一个 addComment
方法:
<?php
namespace App\Policies;
use App\User;
use App\Podcast;
use Illuminate\Auth\Access\HandlesAuthorization;
class PodcastPolicy
{
use HandlesAuthorization;
/**
* 确定用户是否可以在播客中添加评论。
*
* @param \App\User $user
* @param \App\Podcast $podcast
* @return mixed
*/
public function addComment(User $user, Podcast $podcast)
{
return true;
}
}
正如您所看到的,Nova 使用了一个简单的 add{Model}
策略方法命名约定来授权关系行为。
附加 / 分离授权
对于多对多的关系,Nova 使用了 ige 简单的命名规则。 然而,代替 add{Model}
,你可以使用 attach{Model}
/ detach{Model}
naming 规则。例如,假设 Postcast
模型
和 Tag
模型之间有多对多的关系。如果你希望授权用户能够给播客附加 "Tags",你可能需要在播客的策略类上定义一个 attachTag
方法。另外,你也需要在在 tag 的策略上定义 attachPodcast
来反转定义:
<?php
namespace App\Policies;
use App\Tag;
use App\User;
use App\Podcast;
use Illuminate\Auth\Access\HandlesAuthorization;
class PodcastPolicy
{
use HandlesAuthorization;
/**
* 确定用户是否可以将标签附加到播客上。
*
* @param \App\User $user
* @param \App\Podcast $podcast
* @param \App\Tag $tag
* @return mixed
*/
public function attachTag(User $user, Podcast $podcast, Tag $tag)
{
return true;
}
/**
* 确定用户是否可以从播客中分离标签。
*
* @param \App\User $user
* @param \App\Podcast $podcast
* @param \App\Tag $tag
* @return mixed
*/
public function detachTag(User $user, Podcast $podcast, Tag $tag)
{
return true;
}
}
在前面的示例中,我们能够判断用户是否有权限附加到另外一个模型。如果永远不允许某些类型的用户附加给特定的模型,你可以在你的策略类上定义 attachAny{Model}
方法。这样将导致 "Attach" 按钮的不会在 Nova UI 实体上的显示 :
<?php
namespace App\Policies;
use App\User;
use App\Podcast;
use Illuminate\Auth\Access\HandlesAuthorization;
class PodcastPolicy
{
use HandlesAuthorization;
/**
* 确定用户是否可以在播客中附加任何标签
*
* @param \App\User $user
* @param \App\Podcast $podcast
* @return mixed
*/
public function attachAnyTag(User $user, Podcast $podcast)
{
return false;
}
}
多对多的授权
在处理多对多的关系时,请确保在每个涉及的资源的策略类上定义适当的授权策略方法。
禁用授权
如果你的某个 Nova 的资源模型已经有相应的策略,但是你希望禁用该资源的 Nova 授权,我们可以覆盖 authorizable
Nova 资源策略类的方法:
/**
* 定义该资源策略是否启用
*
* @return bool
*/
public static function authorizable()
{
return false;
}
字段
有时候,你可能希望对某些用户组隐藏某些字段。你可以通过 canSee
方法链接到字段的定义,轻松完成这个操作。canSee
该方法接收一个返回 true
或 false
的一个闭包函数。然而这个闭包函数接收
HTTP 的请求对象作为参数:
use Laravel\Nova\Fields\ID;
use Laravel\Nova\Fields\Text;
/**
* 获取资源显示的字段。
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function fields(Request $request)
{
return [
ID::make()->sortable(),
Text::make('Name')
->sortable()
->canSee(function ($request) {
return $request->user()->can('viewProfile', $this);
}),
];
}
上面的例子中,我们在 User
模型里使用 Laravel 的 Authorizable
trait 的 can
方法,来确定授权用户是否被授权 viewProfile
动作。然而,由于代理授权策略方法是 canSee
的常见用例,你可以使用
canSeeWhen
方法实现相同的行为。canSeeWhen
方法与 Illuminate\Foundation\Auth\Access\Authorizable
trait 的 can
方法有相同的方法签名:
Text::make('Name')
->sortable()
->canSeeWhen('viewProfile', $this),
授权 > 「can」方法
想了解更多关于 Laravel 授权和
can
方法的信息,请查看完整的 Laravel 授权文档 。
可关联过滤
如果你希望过滤数据在关联数据中的展示,你可以在 Nova 资源中覆盖 relatableQuery
方法。
例如,如果你的项目中有一个 Comment
资源属于一个 Podcast
资源。在创建一个 Comment
资源时,Nova 将允许你选择他归属的 Podcast
资源。为了在选项中限制用户能选择的 Podcast
,你应该在 Podcast
资源中覆盖 relatableQuery
方法:
/**
* 为资源构建可关联过滤。
*
* 这个查询条件决定了哪些实例可以在关联选项中被选择。
*
* @param \Laravel\Nova\Http\Requests\NovaRequest $request
* @param \Illuminate\Database\Eloquent\Builder $query
* @return \Illuminate\Database\Eloquent\Builder
*/
public static function relatableQuery(NovaRequest $request, $query)
{
return $query->where('user_id', $request->user()->id);
}
Scout 过滤
如果你的应用程序使用了强大的 Laravel Scout 搜索扩展,你可以自定义 Laravel\Scout\Builder
查询实例,然后将其提供个查询服务提供者。如果你要完成这个操作,请复写你资源上的 scoutQuery
方法
/**
* 为给定的资源构建一个 Scout 搜索查询。
*
* @param \Laravel\Nova\Http\Requests\NovaRequest $request
* @param \Laravel\Scout\Builder $query
* @return \Laravel\Scout\Builder
*/
public static function scoutQuery(NovaRequest $request, $query)
{
return $query->where('user_id', $request->user()->id);
}
更多建议: