zycon42/security

Nette框架的安全扩展

v0.2-beta 2014-08-28 19:35 UTC

This package is not auto-updated.

Last update: 2024-09-24 03:09:40 UTC


README

Build Status Latest release

概览

由于我对当前的Nette授权机制不满意,我决定将Symfony/Security移植到Nette。

它主要基于Symfony/Security-Core。遗憾的是,Nette认证机制和Nette\Security\User类与纯Symfony/Security-Core不兼容,因此必须重新编写。

目前该项目仅处理授权,您必须使用Nette类。此外,目前不支持ACL。

有关其内部工作原理的更多信息,请参阅symfony安全文档。

要求

此项目需要php 5.4

安装

安装Zycon42/Security的最佳方式是使用Composer

$ composer require zycon42/security:~0.1

然后您必须在config.neon中启用它

extensions:
	security: Zycon42\Security\DI\SecurityExtension

基本用法

授权的主要入口点是SecurityContext类。示例用法

if (!$securityContext->isGranted('ROLE_ADMIN'))
    throw new ForbiddenRequestException('You need to be admin');

上述代码将在当前用户没有名为ADMIN的角色时拒绝访问。您可以使用IS_AUTHENTICATEDIS_ANONYMOUS代替角色,分别仅授予认证用户或匿名用户访问权限。

您还可以利用isGranted方法的可选二级参数object,并询问当前用户是否可以在给定的资源上执行给定的操作,如下所示

if (!$securityContext->isGranted('EDIT', $post))
    throw new ForbiddenRequestException("You are not able to edit this $post");

投票者

Symfony安全使用投票者的概念,投票者决定用户是否被授予或拒绝。访问决策管理器收集这些投票,并根据它们做出决定。项目包含三个投票者。一个用于角色,第二个用于IS_AUTHENTICATED, IS_ANONYMOUS令牌,最后一个用于我们将稍后讨论的表达式。

使用投票者,您可以轻松扩展支持的属性和对象的范围。例如,您可以实现一个典型的用例,即用户只能编辑自己的帖子。

创建一个新的投票者,实现Zycon42\Security\Authorization\Voters\IVoter接口,然后将其在DIC中注册为特定标记

services:
    foo:
        class: YourVoter
        tags: [security.voter]

当您使用security.voter标记服务时,它将被添加到AccessDecisionManager中作为投票者。

有关投票者及其实现方法的信息,请参阅symfony文档,仅记住我们使用的是来自nette的IIdentity而不是TokenInterface

表达式

为了能够编写更复杂的访问规则,您可以使用表达式。我们使用symfony/expression-language来解析它们。

您可以在其中使用以下函数

  • isAnonymous()如果当前用户未认证则返回true
  • isAuthenticated()如果当前用户已认证则返回true
  • hasRole(string $role)检查用户是否在给定角色中
  • hasPermission($object, $action)检查用户是否有权限在对象上执行操作

您还可以访问一些变量

  • identity当前用户身份
  • user nette用户对象Nette\Security\User
  • object作为isGranted方法的第二个参数传递的对象。
  • roles身份角色的数组

示例用法

$securityContext->isGranted(new Expression("isAuthenticated() && !hasRole('CLIENT')"));

演示者注释

为了能够使用演示者注解来授权/拒绝访问,请在您的受保护演示者中使用此功能,所有需要使用此功能的演示者都应从中派生。

class SecuredPresenter extends BasePresenter
{
    // ... some code

    /**
     * @var PresenterRequirementsChecker
     * @inject
     */
    public $requirementsChecker;

    /**
     * {@inheritdoc}
     */
    public function checkRequirements($element) {
        if (!$this->requirementsChecker->checkRequirement($element, $this->request)) {
            // logged users get 403 and anonymous users get redirect to sign in
            if ($this->user->isLoggedIn()) {
                $expr = $this->requirementsChecker->getFailedExpression();
                throw new ForbiddenRequestException("Request didn't passed security expression \"$expr\"");
            } else {
                $this->redirect('Sign:in', ['backLink' => $this->storeRequest()]);
            }
        }
    }

    // ... some code
}

请记住,不要在派生演示者中覆盖 checkRequirements 方法。

现在您可以使用 @Security 注解注解演示者和其 action/render/handle 方法。小例子:

/**
 * @Security("hasRole('ADMIN')")
 */
class UsersPresenter extends SecuredPresenter
{
    // ... some code
}

或者注解 action 方法

class UsersPresenter extends SecuredPresenter
{
    // ... some code

    /**
     * @Security("hasRole('ADMIN')")
     */
    public function actionEdit($id) {
        // ... implementation
    }
}

在使用演示者注解时请注意,注解是继承的,并且从基类到派生类的顺序进行检查。

注解中的表达式与 isGranted 中的表达式相同,但您还可以访问所有当前请求参数作为变量,并且对象变量包含当前请求。因此,如果您使用将演示者方法参数从 id 转换为实际对象的某些东西,例如添加额外的请求变量 zycon42/param-converters,您将能够编写:

class PostPresenter extends SecuredPresenter
{
    // ... some code

        /**
         * @Security("hasPermission(post, 'EDIT')")
         */
        public function actionEdit(Post $post) {
            // ... implementation
        }
}

配置

在此处您可以找到可能的配置选项及其默认值。

security:
    decisionManager:
        strategy: affirmative
        allowIfAllAbstain: false
        allowIfEqualGrantedDenied: true
    voters:
        role: on
        authenticated: on
        expression: on
    roleHierarchy: false

roleHierarchy 部分中,您可以定义角色如何相互继承。

security:
    roleHierarchy:
        ADMIN: { USER, MANAGER }
        MANAGER: { USER, CLIENT }
        CLIENT: GUEST

请注意,由于 ADMIN 通过 MANAGER 继承自 USER,所以从 USER 继承自 ADMIN 是多余的。但是,这里有每个角色的有效列表:

  • ADMIN: ADMIN, USER, MANAGER, CLIENT, GUEST
  • MANAGER: MANAGER, USER, CLIENT, GUEST
  • CLIENT: CLIENT, GUEST