鍍金池/ 教程/ PHP/ 如何使用訪問(wèn)控制列表(ACLs)
如何以非繼承方式自定義方法
如何創(chuàng)建事件監(jiān)聽(tīng)器
如何以非繼承方式擴(kuò)展一個(gè)類(lèi)
如何記錄消息到不同的文件
如何掌握并創(chuàng)建新的環(huán)境
如何使用 Doctrine DBAL
"XXX is deprecated" E-USER-DEPRECATED 的警告是什么意思?
在登錄表單中使用 CSRF 保護(hù)
如何注冊(cè)自定義 DQL 函數(shù)
如何為表單類(lèi)配置空數(shù)據(jù)
如何嵌入集合表單
如何創(chuàng)建自定義認(rèn)證提供者
如何使用 Apache Router
如何組織配置文件
部署在 Microsoft Azure 云
如何在路由參數(shù)中允許"/"字符
如何在安全,路由,服務(wù)和驗(yàn)證中使用表達(dá)式
如何對(duì)顯示控制臺(tái)信息配置 Monolog
如何為一個(gè) Bundle 創(chuàng)建友好的配置
如何改變默認(rèn)的目標(biāo)路徑行為
如何在運(yùn)行測(cè)試之前自定義引導(dǎo)過(guò)程
如何從路由向控制器傳輸額外的信息
如何從數(shù)據(jù)庫(kù)(實(shí)體提供者)讀取安全用戶(hù)
如何從 Controller 調(diào)用一個(gè)命令
如何創(chuàng)建自定義表單密碼驗(yàn)證器
如何使用內(nèi)建的 PHP Web 服務(wù)器
如何在功能測(cè)試中用 Token 模擬認(rèn)證
配置 Session 文件的保存目錄
理解前端控制器、內(nèi)核及環(huán)境如何協(xié)同工作
如何實(shí)現(xiàn)一個(gè)簡(jiǎn)單的注冊(cè)表單
如何使用 Doctrine 擴(kuò)展:Timestampable, Sluggable, Translatable 等等
如何使用多個(gè)實(shí)體管理器和連接
如何自定義表單渲染
如何安裝第三方 Bundles
使用預(yù)認(rèn)證安全防火墻
如何簡(jiǎn)化多個(gè) Bundle 的配置
會(huì)話代理實(shí)例
安裝 Composer
如何冒充一個(gè)用戶(hù)
如何注冊(cè)一個(gè)新的請(qǐng)求格式和 MIME 類(lèi)型
如何在功能測(cè)試中使用分析器
如何在服務(wù)容器內(nèi)設(shè)置外部參數(shù)
如何重寫(xiě) Symfony 默認(rèn)的目錄結(jié)構(gòu)
如何在一個(gè) Symfony 控制器中創(chuàng)建一個(gè) SOAP 的 Web 服務(wù)
如何使用序列化
部署在 Platform.sh
升級(jí)一個(gè)副版本
如何寫(xiě)一個(gè)自定義的 Twig 擴(kuò)展
如何在 SubVersion 中創(chuàng)建并保存一個(gè) Symfony 項(xiàng)目
使用 PHP 庫(kù)聯(lián)合,編譯和最小化 Web 資產(chǎn)
如何創(chuàng)建一個(gè)自定義的數(shù)據(jù)收集器
如何使用和注冊(cè)命名空間路徑
如何使用 Monolog 記錄日志
如何建立一個(gè)傳統(tǒng)的登錄表單
如何強(qiáng)制路由總是使用 HTTPS 或者 HTTP
如何在模板中使用 PHP 而不是 Twig
如何動(dòng)態(tài)選擇密碼加密算法
避免匿名用戶(hù)開(kāi)始 Session 會(huì)話
如何測(cè)試 Doctrine 倉(cāng)庫(kù)
如何在功能測(cè)試中測(cè)試一封電子郵件被發(fā)送
Symfony2 與 Symfony1 的區(qū)別
使用結(jié)尾反斜線重定向 URL
(configuration)如何在數(shù)據(jù)庫(kù)中使用 PdoSessionHandler 存儲(chǔ) Sessions
如何使用匹配器有條件地啟用分析器
部署在 Heroku 云
如何不用自定義控制器配置重定向
如何在 Bundle 內(nèi)部加載服務(wù)配置
如何處理不同的錯(cuò)誤級(jí)別
如何在應(yīng)用中保護(hù)服務(wù)和方法
如何對(duì)表單單元測(cè)試
如何把命令定義為服務(wù)
如何配置 Monolog 從日志中排除 404 錯(cuò)誤
如何使用控制臺(tái)
如何測(cè)試與數(shù)據(jù)庫(kù)交互的代碼
如何在路由中使用除了 GET 和 POST 的 HTTP 方法
如何使用云服務(wù)發(fā)送電子郵件
如何創(chuàng)建一個(gè)控制臺(tái)命令
在遺留的應(yīng)用上使用 Symfony Session
如何使用高級(jí)的訪問(wèn)控制列表
如何不用一個(gè)自定義的控制器渲染一個(gè)模板
如何重寫(xiě)部分 Bundle
升級(jí)一個(gè)主版本
安全訪問(wèn)控制是如何工作的
如何使用 Bundle 的繼承來(lái)重寫(xiě)部分 Bundle
如何使用 Voter 檢查用戶(hù)權(quán)限
如何為多個(gè) Doctrine 的實(shí)現(xiàn)提供模型類(lèi)
如何使用作用域
如何部署一個(gè) Symfony 應(yīng)用
如何用 "inherit-data" 減少代碼冗余
如何注冊(cè)事件監(jiān)聽(tīng)器和訂閱
使用 Bower 安裝 Symfony
如何創(chuàng)建一個(gè)自定義路由加載器
如何創(chuàng)建一個(gè)自定義的驗(yàn)證限制
在獨(dú)立注入類(lèi)中使用參數(shù)
如何使用 Assetic 和 Twig Functions 進(jìn)行圖像優(yōu)化
如何利用表單事件動(dòng)態(tài)修改表單
如何在過(guò)濾器的前后設(shè)置事件分發(fā)器
如何在 Bundle 中使用 Compiler Passes
緩存包含 CSRF 保護(hù)表單的頁(yè)面
如何注入變量到所有的模板(如全局變量)
如何創(chuàng)建一個(gè)自定義表單域類(lèi)型
如何限定防火墻使其只允許通過(guò)指定請(qǐng)求
如何把 Controller 定義為服務(wù)
如何使用 Gmail 發(fā)送郵件
升級(jí)一個(gè)補(bǔ)丁版本
如何創(chuàng)建一個(gè)表單類(lèi)型擴(kuò)展
如何對(duì)不同的 URL 強(qiáng)制使用 HTTPS 或者 HTTP
如何使用 Varnish 加速我的 Web 站點(diǎn)
如何定義虛擬類(lèi)和接口之間的關(guān)系
如何自定義登錄表單
如何測(cè)試多個(gè)客戶(hù)端的交互
PSR-7 Bridge
如何使用 YUI Compressor 裁剪 Javascripts 和 Stylesheets
在用戶(hù)的 Session 中使用局部 "Sticky"
如何定制錯(cuò)誤頁(yè)
如何從已存在的數(shù)據(jù)庫(kù)中生成實(shí)體
如何用 Doctrine 上傳文件
可復(fù)用 Bundles 的最佳實(shí)踐
如何發(fā)送一封電子郵件
如何將 Assetic Filter 應(yīng)用到具體的文件擴(kuò)展名上
切換分析器存儲(chǔ)
如何上傳文件
限制 Session 元數(shù)據(jù)的寫(xiě)入
如何使用多用戶(hù)提供者
如何使用數(shù)據(jù)轉(zhuǎn)換
配置一個(gè) Web 服務(wù)器
如何編程訪問(wèn)分析器數(shù)據(jù)
如何在路由中使用服務(wù)容器參數(shù)
如何在控制臺(tái)生成 URL 和發(fā)送郵件
如何將你的開(kāi)發(fā)環(huán)境優(yōu)化為調(diào)試環(huán)境
如何在控制臺(tái)命令中啟用日志
如何在功能測(cè)試中模擬 HTTP 認(rèn)證
如何使用 API 驗(yàn)證用戶(hù)
如何移除 AcmeDemoBundle
控制臺(tái)命令
如何配置 Symfony 使其工作在負(fù)載均衡和反轉(zhuǎn)代理
如何添加“記住我”登錄功能
如何使用 Assetic 進(jìn)行資產(chǎn)管理
如何限定防火墻使其接受指定主機(jī)
如何使用訪問(wèn)控制列表(ACLs)
如何裁剪 CSS/JS 文件(使用 UglifyJS 和 UglifyCSS)
如何緩存電子郵件
如何使用 submit() 函數(shù)處理表單提交
如何在 Git 中創(chuàng)建并保存一個(gè) Symfony 項(xiàng)目
如何創(chuàng)建自定義用戶(hù)提供者
如何對(duì)電子郵件錯(cuò)誤配置 Monolog
如何在開(kāi)發(fā)時(shí)使用電子郵件

如何使用訪問(wèn)控制列表(ACLs)

在復(fù)雜的申請(qǐng)中,你可能經(jīng)常面臨訪問(wèn)權(quán)限決策不僅僅取決于請(qǐng)求者本人(Token)還牽涉到了被申請(qǐng)的對(duì)象的問(wèn)題。這也是 ACLs 系統(tǒng)被制作出來(lái)的原因所在。

ACLs的替代選擇

使用 ACL 并不是細(xì)微之事,它的的確確對(duì)使用有簡(jiǎn)化功能。當(dāng)然,它可能會(huì)濫殺無(wú)辜。如果你的判定邏輯只是被簡(jiǎn)單的代碼來(lái)描述(比如檢查這個(gè)博客是否被一個(gè)現(xiàn)在的使用者所擁有> ),那么就考慮使用 voters。一個(gè) voter 可以通過(guò)表決來(lái)傳遞對(duì)象,通過(guò)這些,你就可以做出復(fù)雜的決定和更高效地執(zhí)行你的 ACL。此外,強(qiáng)制批準(zhǔn)(比如 isGranted 部分)就會(huì)看起來(lái)和你所看到的這個(gè)條目極其相似,但是你的 voter 類(lèi)就會(huì)在幕后控制判定邏輯了,而不是 ACL 系統(tǒng)。

想象你在設(shè)計(jì)一個(gè)博客系統(tǒng),而你的使用者可以評(píng)論你的工作?,F(xiàn)在,如果你希望一個(gè)使用者能夠修改編輯他們自己的評(píng)論,但并不是所有的用戶(hù);此時(shí),你可以修改所有的評(píng)論。在這種情況下,comment 就會(huì)處理域名對(duì)象,同時(shí)你會(huì)獲得權(quán)限。你可以采用多種方式來(lái)完成這個(gè) Symfony,兩個(gè)基本的方式如下:

  • Enforce security in your business methods:基本上講,這個(gè)方法意味著在每一個(gè) Comment 之間制作一個(gè)參照,比較這些使用者提供的令牌,就可以做出決策。

  • Enforce security with roles:在這種方法中,你可以為每一個(gè) Comment 對(duì)象添加一些角色。比如 ROLE_COMMENT_1, ROLE_COMMENT_2 等等。

每種方法都非常有效。然而,它們結(jié)合了你的授權(quán)邏輯來(lái)負(fù)責(zé)你的商業(yè)代碼,會(huì)限制你的代碼的可通用型,因此這就增加了單元調(diào)試難度。此外,你可能會(huì)撞上一些問(wèn)題,如果用戶(hù)只有一個(gè)簡(jiǎn)單的域名對(duì)象的話。

幸運(yùn)的是,這里有一種更好的方式,你在下面就可以看到。

引導(dǎo)指令

現(xiàn)在,在你能夠采取行動(dòng)之前,你需要做一些引導(dǎo)指令。首先,你需要安裝你要實(shí)用的 ACL 系統(tǒng)的連接。

YAML:

# app/config/security.yml
security:
    acl:
        connection: default

XML:

<!-- app/config/security.xml -->
<acl>
    <connection>default</connection>
</acl>

PHP:

// app/config/security.php
$container->loadFromExtension('security', 'acl', array(
    'connection' => 'default',
));

ACL 體系要求一種連接關(guān)系,這種連接關(guān)系可以由 DBAL 來(lái)提供,也可以由 MongoDB(使用 MongoDBAclBundle)來(lái)提供。然而,那并不意味著你必須用 DoctrineORM 或者 ODM 來(lái)組織你的域?qū)ο?。你可以用任意組織對(duì)象的方法和手段,比如 DoctrineORM,MongoDB ODM,Propel,rawSQL 等等。選擇權(quán)在你手里。

在連接方式確定好之后,你就需要來(lái)輸入基礎(chǔ)的數(shù)據(jù)結(jié)構(gòu)了。幸運(yùn)的是,有一項(xiàng)任務(wù)專(zhuān)門(mén)處理這種情況,只需要運(yùn)行一下面的指令就可以了:

$ php app/console init:acl

開(kāi)始工作

回到最開(kāi)始的小例子上去,現(xiàn)在你可以對(duì)它運(yùn)用 ACL 技術(shù)了。

一旦 ACL 被建立起來(lái),你就可以通過(guò)建立一個(gè) Access Control Entry,來(lái)向你的用戶(hù)提供信息獲取通道。當(dāng)然同時(shí)就可以穩(wěn)固你的使用者和你的工作實(shí)體之間的聯(lián)系了。

建立一個(gè) ACL,添加一個(gè) ACE

// src/AppBundle/Controller/BlogController.php
namespace AppBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
use Symfony\Component\Security\Acl\Domain\ObjectIdentity;
use Symfony\Component\Security\Acl\Domain\UserSecurityIdentity;
use Symfony\Component\Security\Acl\Permission\MaskBuilder;

class BlogController extends Controller
{
    // ...

    public function addCommentAction(Post $post)
    {
        $comment = new Comment();

        // ... setup $form, and submit data

        if ($form->isValid()) {
            $entityManager = $this->getDoctrine()->getManager();
            $entityManager->persist($comment);
            $entityManager->flush();

            // creating the ACL
            $aclProvider = $this->get('security.acl.provider');
            $objectIdentity = ObjectIdentity::fromDomainObject($comment);
            $acl = $aclProvider->createAcl($objectIdentity);

            // retrieving the security identity of the currently logged-in user
            $tokenStorage = $this->get('security.token_storage');
            $user = $tokenStorage->getToken()->getUser();
            $securityIdentity = UserSecurityIdentity::fromAccount($user);

            // grant owner access
            $acl->insertObjectAce($securityIdentity, MaskBuilder::MASK_OWNER);
            $aclProvider->updateAcl($acl);
        }
    }
}

在上面的代碼段中有一些重要的實(shí)施策略。現(xiàn)在,我僅僅希望能強(qiáng)調(diào)兩點(diǎn):

首先,你可能注意到 ->createAcl() 不直接接受域?qū)ο?,而只接?ObjectIdentityInterface 的啟用。當(dāng)你手里沒(méi)有實(shí)際的區(qū)域?qū)ο髮?shí)例的時(shí)候,這個(gè)附加步驟間接地允許你能夠和 ACLs 交互。這在你想要檢查一大批對(duì)象的權(quán)限的時(shí)候,將會(huì)起到很大的作用。

另一個(gè)有趣的部分在于 ->insertObjectAce() 的調(diào)用。在例子里,我們可以授予直接聯(lián)機(jī)的用戶(hù)以修改評(píng)論的權(quán)限。而 MaskBuilder::MASK_OWNER 是一個(gè)提前定義的整型位掩碼;不必?fù)?dān)心掩碼生成器會(huì)抽象大部分細(xì)節(jié),但是這種技術(shù)會(huì)幫助你從數(shù)據(jù)庫(kù)里得到一系列不同的權(quán)限數(shù)據(jù),從而讓你的表現(xiàn)能夠顯得更漂亮一些。

ACEs 的檢查順序是很有意義的,作為一項(xiàng)通用的準(zhǔn)則,你應(yīng)該在最開(kāi)始設(shè)立更多的入口。

檢測(cè)通道

// src/AppBundle/Controller/BlogController.php

// ...

class BlogController
{
    // ...

    public function editCommentAction(Comment $comment)
    {
        $authorizationChecker = $this->get('security.authorization_checker');

        // check for edit access
        if (false === $authorizationChecker->isGranted('EDIT', $comment)) {
            throw new AccessDeniedException();
        }

        // ... retrieve actual comment object, and do your editing here
    }
}

在這個(gè)例子里,你可以檢測(cè)用戶(hù)是否有編輯權(quán)限。在 Symfony 內(nèi)部,Symfony 會(huì)分配權(quán)限給幾個(gè)整型的位掩碼,然后檢測(cè)用戶(hù)是否擁有這些碼。

你可以建立起 32 位的權(quán)限碼(取決于你的 OS,PHP 的碼位可以從 30 到 32 不等)。此外,你也可以定義累加權(quán)限。

累加權(quán)限

在上面的第一個(gè)例子中,你只能保證用戶(hù)得到 owner 的基本權(quán)限。盡管這樣可以有效地管理用戶(hù)的基礎(chǔ)操作權(quán)限,比如可視,編輯等等。但是有時(shí)候我們希望用戶(hù)得到的權(quán)限更加明確清晰。

通過(guò)結(jié)合幾個(gè)基本權(quán)限,MaskBuilder 能夠被用于建立位掩碼。

$builder = new MaskBuilder();
$builder
    ->add('view')
    ->add('edit')
    ->add('delete')
    ->add('undelete')
;
$mask = $builder->get(); // int(29)

這個(gè)整型位掩碼能夠被用于保證用戶(hù)權(quán)限添加的成功。

$identity = new UserSecurityIdentity('johannes', 'Acme\UserBundle\Entity\User');
$acl->insertObjectAce($identity, $mask);

現(xiàn)在用戶(hù)可以使用可視,編輯,刪除以及取消刪除對(duì)象了。