用户授权(权限管理)

未匹配的标注

Masonite 也提供一种简单的方式授权用户对资源操作。基于两个概念:gates 和策略。 Gates 顾名思义就是一种授权安检,在操作资源前需要校验用户是否有权访问。策略是一种围绕模型进行分组授权逻辑方式。

Gates

Gates are simple callable that will define if a user is authorized to perform a given action.
A handy Gate facade is available to easily manipulate gates.

Registering Gates

Gates receive a user instance as their first argument and may receive additionals arguments such as
a Model instance. You needs to define Gates in boot() method of your service provider.

In the following example we are adding gates to verify if a user can create and update posts. Users
can create posts if they are administrators and can update posts they have created only.

from masonite.facades import Gate

class MyAppProvider(Provider):

    def boot(self):
        Gate.define("create-post", lambda user: user.is_admin)
        Gate.define("update-post", lambda user, post: post.user_id == user.id)

You can then check if a gate exists or has been registed by using has() which is returning
a boolean:

Gate.has("create-post")

提示:If a unknown gate is used a GateDoesNotExist exception will be raised.

Authorizing Actions

Then anywhere (often in a controller) in your code you can use those gates to check if the current authenticated user is authorized to perform the given action defined by the gate.

Gates exposes different methods to perform verification: allows(), denies(), none(), any(), authorize() inspect().

allows(), denies(), none() and any() return a boolean indicating if user is authorized

if not Gate.allows("create-post"):
    return response.redirect("/")

# ...
post = Post.find(request.input("id"))
if Gate.denies("update-post", post):
    return response.redirect("/")

# ...
Gate.any(["delete-post", "update-post"], post)

# ...
Gate.none(["force-delete-post", "restore-post"], post)

authorize() does not return a boolean but will raise an AuthorizationException exception instead that will be rendered as an HTTP response with a 403 status code.

Gate.authorize("update-post", post)
# if we reach this part user is authorized
# else an exception has been raised and be rendered as a 403 with content "Action not authorized".

Finally for better control over the authorization check you can analyse the response with inspect():

response = Gate.inspect("update-post", post)
if response.allowed():
     # do something
else:
     # not authorized and we can access message
     Session.flash("errors", response.message())

Via the User Model

Authorizes class can be added to your User model to allow quick permission checks:

from masonite.authentication import Authenticates
from masonite.authorization import Authorizes

class User(Model, Authenticates, Authorizes):
    #..

A fluent authorization api will now be available on User instances:

user.can("delete-post", post)
user.cannot("access-admin")
user.can_any(["delete-post", "force-delete-post"], post)

All of those methods receive the gate name as first argument and then some additional arguments if required.

With a given user

You can use the for_user() method on the Gate facade to make the verification against a given user instead
of the authenticated user.

from masonite.facades import Gate

user = User.find(1)
Gate.for_user(user).allows("create-post")

Gate Hooks

During the gate authorization process, before and after hooks can be triggered.

A before hook can be added like this:

# here admin users will always be authorized based on the boolean value of this response
Gate.before(lambda user, permission : user.role == "admin")

The after hook works the same way:

Gate.after(lambda user, permission, result : user.role == "admin")

If the after callback is returning a value it will take priority over the gate result check.

Policies

Policies are classes that organize authorization logic around a specific model.

Creating Policies

You can run the craft command:

$ python craft policy AccessAdmin

You can also create a policy with a set of predefined gates by using the --model flag:

$ python craft policy Post --model

A model policy comes with common actions that we can perform on a model:

from masonite.authorization import Policy

class PostPolicy(Policy):
    def create(self, user):
        return False

    def view_any(self, user):
        return False

    def view(self, user, instance):
        return False

    def update(self, user, instance):
        return False

    def delete(self, user, instance):
        return False

    def force_delete(self, user, instance):
        return False

    def restore(self, user, instance):
        return False

You are free to add any other methods on your policies:

from masonite.authorization import Policy

class PostPolicy(Policy):
    #.. 

    def publish(self, user):
        return user.email == "admin@masonite.com"

Registering Policies

Then in your service provider (as for defining gates) you should register the policies and bind them with a model:

from masonite.facades import Gate
from app.models.Post import Post
from app.models.User import User

from app.policies.PostPolicy import PostPolicy
from app.policies.UserPolicy import UserPolicy

class MyAppProvider(Provider):

    #..

    def register(self):
        Gate.register_policies(
            [(Post, PostPolicy), (User, UserPolicy)],
        )

An example policy for the Post model may look like this:

from masonite.authorization import Policy

class PostPolicy(Policy):
    def create(self, user):
        return user.email == "idmann509@gmail.com"

    def view(self, user, instance):
        return True

    def update(self, user, instance):
        return user.id == instance.user_id

提示:If an unknown policy is used then a PolicyDoesNotExist exception will be raised.

Authorizing Actions

You can then use the Gate facade methods to authorize actions defined in your policies. With the previously defined PostPolicy we could make the following calls:

from masonite.facades import Gate

post = Post.find(1)
Gate.allows("update", post)
Gate.denies("view", post)
Gate.allows("force_delete", post)

The create() or view_any() methods do not take a model instance, that is why the model class should be
provided so that Gate mechanism can infer from which policy those methods are belonging to.

Gate.allows("create", Post)
Gate.allows("view_any", Post)

Gates 是简单的可调用函数,它将定义用户是否被授权执行给定的操作。

本文章首发在 LearnKu.com 网站上。

本译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。

原文地址:https://learnku.com/docs/masonite/4.0/fe...

译文地址:https://learnku.com/docs/masonite/4.0/fe...

上一篇 下一篇
贡献者:2
讨论数量: 0
发起讨论 只看当前版本


暂无话题~