认证和授权

本章由Eric Rasmussen撰写。

Pyramid 具有内置的身份验证和授权能力,可以轻松地限制处理程序操作。以下是您通常需要采取的步骤的概述:

  1. 在模型中创建一个根工厂,将allow/deny指令与组和权限关联起来。
  2. Create users and groups in your model
  3. 创建回调函数以检索用户根据其用户ID订阅的组列表
  4. 生成一个“禁止的视图”,在引发禁止的异常时将调用该视图。
  5. 创建一个登录操作,该操作将检查用户名/密码,并在成功时记住用户。
  6. Restrict access to handler actions by passing in a permission='somepermission' argument to @view_config .
  7. 在你的配置中把它们连接起来

您可以通过向模型中添加导入语句和自定义根工厂来开始:

1
2
3
4
5
6
7
8
9
from pyramid.security import Allow, Everyone

class RootFactory(object):
    __acl__ = [ (Allow, Everyone, "everybody"),
                (Allow, "basic", "entry"),
                (Allow, "secured", ("entry", "topsecret"))
              ]
    def __init__(self, request):
        pass

自定义根工厂生成的对象将用作发送到Web应用程序的请求的上下文。根工厂的第一个属性是acl或访问控制列表。它是一个元组列表,其中包含处理请求的指令(如allow或deny)、授予或拒绝访问资源的组以及与该组关联的权限(或可选的权限元组)。

上面的访问控制列表示例表明,我们将允许每个人查看“所有人”权限的页面,基本组的成员查看“条目”权限限制的页面,安全组的成员查看“条目”或“TopSecret”权限限制的页面。特殊主体“Everyone”是一个内置功能,允许任何访问您站点的人(称为主体)访问给定资源。

对于要登录的用户,可以创建一个处理程序来验证通过表单提交的登录名和密码(或任何其他条件)。您通常希望添加以下导入:

from pyramid.httpexceptions import HTTPFound
from pyramid.security import remember, forget

根据模型验证用户的登录名和密码后,可以将头设置为“记住”用户的ID,然后可以将用户重定向到其尝试访问的主页或URL::

# retrieve the userid from the model on valid login
headers = remember(self.request, userid)
return HTTPFound(location=someurl, headers=headers)

Note that in the call to the remember function, we're passing in the user ID we retrieved from the database and stored in the variable 'userid' (an arbitrary name used here as an example). However, you could just as easily pass in a username or other unique identifier. Whatever you decide to "remember" is what will be passed to the groupfinder callback function that returns a list of groups a user belongs to. 如果你进口 authenticated_userid , which is a useful way to retrieve user information in a handler action, it will return the information you set the headers to "remember".

要注销用户,您可以“忘记”他们,并使用httpfound重定向到另一个URL::

headers = forget(self.request)
return HTTPFound(location=someurl, headers=headers)

在使用权限限制处理程序操作之前,需要使用回调函数返回用户ID所属的组列表。下面是在模型中实现它的一种方法,在本例中,假设您有一个groups对象具有groupname属性,一个users对象具有mygroups与groups的关系:

def groupfinder(userid, request):
    user = Users.by_id(userid)
    return [g.groupname for g in user.mygroups]

例如,您现在可以导入并使用@action decorator按权限进行限制,并验证user id以从请求中检索用户的ID::

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
from pyramid_handlers import action
from pyramid.security import authenticated_userid
from models import Users

class MainHandler(object):
    def __init__(self, request):
        self.request = request

    @action(renderer="welcome.html", permission="entry")
    def index(self):
        userid = authenticated_userid(self.request)
        user = Users.by_id(userid)
        username = user.username
        return {"currentuser": username}

这为我们提供了一种非常简单的方法来限制处理程序操作,并获取有关用户的信息。本例假设我们有一个用户类,该类具有一个方便类方法,该方法由_id调用以返回用户对象。然后,您可以访问模型中定义的对象的任何属性(例如用户名、电子邮件地址等),并将这些属性作为返回语句中的字典键/值传递给模板。

如果希望在引发禁止的异常时调用特定的处理程序操作,则需要添加禁止的视图。这是前面提到的,但为了完整:

1
2
3
4
5
@view_config(renderer='myapp:templates/forbidden.html',
             context='pyramid.exceptions.Forbidden')
@action(renderer='forbidden.html')
def forbidden(request):
    ...

最后一步是配置uuu init_uuu.py以使用授权策略。确保添加这些导入:

from pyramid.authentication import AuthTktAuthenticationPolicy
from pyramid.authorization import ACLAuthorizationPolicy
from .models import groupfinder

在您的主函数中,您需要定义认证策略,以便在对配置程序的调用中包含它们:

1
2
3
4
5
6
7
8
authn_policy = AuthTktAuthenticationPolicy('secretstring',
   callback=groupfinder)
authz_policy = ACLAuthorizationPolicy()
config = Configurator(settings=settings,
   root_factory='myapp.models.RootFactory',
   authentication_policy=authn_policy,
   authorization_policy=authz_policy)
config.scan()

Pyramid 中的认证和授权功能与使用 Pylons 和重新部署相比非常容易入门。其优点是更容易维护代码和内置方法来处理诸如记住或忘记用户、设置权限以及轻松修改GroupFinder回调以使用模型等常见任务。对于可以管理预先在根工厂中设置权限并限制单个处理程序操作的情况,这是迄今为止最简单的启动和运行方式,同时仍然通过模型提供强大的用户和组管理功能。

但是,如果应用程序需要创建/编辑/删除权限(不只是通过组成员身份访问),或者需要使用高级谓词,则可以构建自己的身份验证系统(有关详细信息,请参阅Pyramid文档)或集成现有系统(如repoze.what)。

如果您想使用谁的身份验证程序和配置,还可以在Pyramid的授权系统中使用“repoze.who”。