Dexterity开发手册:第六章 第10节 权限

Dexterity开发手册:第六章 第10节 权限
设置 add permissions, view permissions 和字段级别的查看、编辑权限
Plone的安全体系是基于采用权限来保护相关操作(象访问一个视图,查看一个字段、修改一个字段或者添加一种类型的内容等等),这些权限授权到角色,角色又被指派到用户或用户组。在内容类型开发中,权限典型的被用在三个方面:
  • 一个内容类型或一组相关的内容类型通常有一个定制的 add permission 权限用来控制谁能添加这种内容类型。
  • 视图(包括表单) 用定制的权限保护。
  • 独立的字段被权限保护,以便某些人能查看或编辑某字段,而其他人不能。
创建新的权限非常容易,然而,应尽可能应用系统的标准权限。
标准权限Standard permissions
标准权限定义在 Product.Five包的 permissions.zcml (parts/omelette/Products/Five/permissions.zcml)。这儿每个权限定义将有一个简短 id (也称为 Zope 3 permission id) 和一个长的title (也称为 the Zope 2 permission title)。由于历史原因,某些地方采用id,某些地方采用title,为了区分,请记住下面规则:
  • 定义在 ZCML 中的浏览器视图或者通过一个 grok.require() 申明的权限采用 Zope 3 permission id
  • zope.security.checkPermission() 进行安全检查时采用 Zope 3 permission id
  • Dexterity的add_permission FTI 变量用 Zope 3 permission id.
  • 这个GenericSetup handler的rolemap.xml 和 workflows 采用Zope 2 permission title.
  • AccessControl's getSecurityManager().checkPermission() 进行安全检查,包括 portal_membership tool的方法, 采用 Zope 2 permission title.
最频繁使用的权限列出在下面,Zope 2 permission title显示在()中:
  • zope2.View (View) 用于控制访问到一个内容对象的标准视图
  • zope2.DeleteObjects (Delete objects) 用于控制在一个容器中删除子对象的能力。
  • cmf.ModifyPortalContent (Modify portal content) 用于控制对内容对象的写访问。
  • cmf.ManagePortal (Manage portal)用于控制访问管理面板。
  • cmf.AddPortalContent (Add portal content) 用于控制添加一个内容到文件夹的标准权限。
  • cmf.SetOwnProperties (Set own properties)用于控制用户编辑自己的会员属性。
  • cmf.RequestReview (Request Review)用于典型的工作流事物,控制允许用户提交内容到审核。
  • cmf.ReviewPortalContent (Review portal content)用于允许审核角色控制发布还是拒绝内容。
标准角色
象权限一样,可以方便创建定制的角色。 (用 rolemap.xml GenericSetup import step完成,参考 CMFPlone's version of this file for an example),应该尽可能地采用标准的角色。
Plone中标准角色是:
  • Anonymous, 一个虚拟的角色,用来表示未登录的用户。
    注意如果一个权限被授予到 Anonymous,这意味着该权限对任何人有效。
    • Authenticated, 一个虚拟角色用来表示已登录的用户。
    • Owner, 被自动授予到一个对象的创建者。
    • Manager, 表现超级用户/管理员。所有没有授予给Anonymous的权限被授予给Manager.
    • Reviewer, 内容的审核者,不同于site administrators。可以通过共享tab本地授予Reviewer角色,它的显示名称是 Can review.
    • Member, 表示标准的 Plone 会员
    另外,有三个角色只被用于本地角色。通过共享tab来授予到特定的用户和组,三个本地角色的名称被命名为大多数用户很好理解的方式:
    • Reader, 又称为 Can view, 针对查看内容授予权限。作为一条基本规则,这个 Reader 角色应该有 ViewAccess contents information 的权限。
    • Editor, 又称为 Can edit,针对编辑内容授予权限。作为一条基本规则,这个 Editor 角色应用有 Modify portal content 权限。
    • Contributor,又称为 Can add,针对添加新的内容授予权限。 作为一条基本规则,这个 Contributor 角色应该有Add portal content 权限并且也要有任何内容类型特别要求的 add permissions globally (例如在 rolemap.xml中被授予),尽管这些权限多数时间是被工作流管理。
    在代码中执行权限检查
  • 有时有必要在代码中显式检查权限,比如在视图中。权限检查总是在一个上下文对象上检查一个权限,权限可以用工作流来修改。
  • 不要制造安全申明直接到用户角色,而应该总是申明到指定的权限,然后将权限授予到特定的角色。
    作为例子,让我们在Session类型的视图中显示一条消息,当用户有cmf.RequestReview 权限时,显示出来。在 session.py中,我们更新这个 View class 如下: from zope.security import checkPermission class View(dexterity.DisplayForm): grok.context(ISession) grok.require('zope2.View') def canRequestReview(self):   return checkPermission('cmf.RequestReview', self.context)并且在 session_templates/view.pt 模板中添加: <div class="discreet" tal:condition="view/canRequestReview" i18n:translate="suggest_review"> Please submit this for review. </div>创建定制的权限
  • 尽管标准的权限常用来控制基本操作(如view, modify, delete, review),有时,创建新的权限是有用的。组合定制的工作流和定制的权限能最大限度地任意定制内容审核周期和数据输入应用。 它们的组合也是控制谁能添加什么内容的重要方法。
  • 创建定制权限最简短的方法是采用 collective.autopermission 包,只需在ZCML中用<permission />的形式定义权限即可。
    collective.autopermission 在 Zope 2.12后被毁弃,它的功能已全部归并到Zope自身。
    作为一个例子,让我们为Session类型创建某些定制的权限。我们将创建一个新的add permission,以便所有会员能提交一个session 到一个 program;还将添加一个权限,它被用来让审核者编辑Session类型的指定字段。 首先,我们需要依赖 collective.autopermission,在 setup.py申明: install_requires=[ ... 'collective.autopermission', ],
    肯定 collective.autopermission的配置在任何定制的权限前被included,在我们的例子中,这个 <includeDependencies /> 行来包括该配置。
    接着,我们创建一个名为 permissions.zcml 文件来设置自定义的权限(当然我们也能将这些权限直接放在 configure.zcml).。在configure.zcml中,我们需要包括这个文件在 <includeDependencies /> 行后面。 <include file="permissions.zcml" />
    注意:所有权限定义需要在 <grok:grok package="." /> 行之前,否则,当你用grok.require()语句来引用权限时,会报错。
    这个 permissions.zcml 看起来象这样: <configure xmlns="http://namespaces.zope.org/zope" i18n_domain="example.conference"> <permission id="example.conference.AddSession" title="example.conference: Add session" /> <permission id="example.conference.ModifyTrack" title="example.conference: Modify track" /> </configure>缺省新权限仅仅被授予 Manager 角色。对于设置其他的缺省值,我们可以通过 rolemap.xml GenericSetup 导入步骤来实现权限对角色的映射。 在 profiles/default/rolemap.xml, 我们有如下: <?xml version="1.0"?> <rolemap> <permissions> <permission name="example.conference: Add session" acquire="True"> <role name="Owner"/> <role name="Manager"/> <role name="Member"/> <role name="Contributor"/> </permission> <permission name="example.conference: Modify track" acquire="True"> <role name="Manager"/> <role name="Reviewer"/> </permission> </permissions> </rolemap>
    在这个文件中权限标识采用 Zope 2 权限的 title 代替 Zope 3权限id
    内容类型添加权限 Dexterity 内容类型的 add permissions 被设置在FTI中,采用这个 add_permission 属性。这个可以通过web或者 GenericSetup import step来修改。 为使得 Session type采用我们新的权限,我们修改profiles/default/example.conference.session.xml文件的 add_permission 行为: <property name="add_permission">example.conference.AddSession</property>保护视图和表单视图和其他浏览器资源(like viewlets or portlets)能够被权限保护,可以在ZCML中<browser:page />里用permission属性,或者用 grok.require() 语句。 我们在视图中已看到下面的语句: class View(grok.View): grok.context(IPresenter) grok.require('zope2.View')我们可以用一个定制的权限名称作为 grok.require()的参数,我们也可以用特殊的 zope.Public 权限来使得视图允许所有人访问。 保护表单字段 在schema中独立的字段可以用 一个read permission 和一个 write permission来保护。这个read permission 用于控制访问字段的值和控制URL traversal, 能被用于当显示表单时控制字段是否出现。 Write permissions 用于控制一个给定的字段是否出现在添加/编辑表单中。 这两种情况下,读和写权限被用类似于我们之前看到的form widget hints的语句附加到schema当中。这个 read_permission()write_permission() 语句来自于 plone.directives.dexterity 包。 作为一个例子,我们添加一个字段来为一个session的Session reviewers者记录跟踪信息。我们将保存在父Program对象的有效跟踪词汇在一个text字段中,以便这个Program创建者能选择有效的跟踪。 首先,我们在 program.py中,添加下面内容到 IProgram schema 中: form.widget(tracks=TextLinesFieldWidget) tracks = schema.List( title=_(u"Tracks"), required=True, default=[], value_type=schema.TextLine(), )这个 TextLinesFieldWidget 是用于在一个text区编辑文本行列表,它被导入作为: from plone.z3cform.textlines.textlines import TextLinesFieldWidget接着,我们在session.py中添加一个词汇: from Acquisition import aq_inner, aq_parent from zope.schema.interfaces import IContextSourceBinder from zope.schema.vocabulary import SimpleVocabulary ... @grok.provider(IContextSourceBinder) def possibleTracks(context): # we put the import here to avoid a circular import from example.conference.program import IProgram while context is not None and not IProgram.providedBy(context): context = aq_parent(aq_inner(context)) values = [] if context is not None and context.tracks: values = context.tracks return SimpleVocabulary.fromValues(values)这个词汇发现最近的 IProgram (在添加表单中,这个 context 将是 Program对象,但是在编辑表单中,它将是一个 Session对象,因此我们需要检查上层父对象) 并用它的跟踪变量作为词汇。 接着,我们添加一个字段到ISession 接口,用相关的写权限保护它: dexterity.write_permission(track='example.conference.ModifyTrack') track = schema.Choice( title=_(u"Track"), source=possibleTracks, required=False, )这个 dexterity module是 plone.directives.dexterity 包的根,被导入作为: from plone.directives import dexterity通过这样,有 example.conference: Modify track 权限的用户应该能为一个session编辑跟踪信息。而对其他身份的用户,在编辑表单中,该字段被隐藏。
设置