安全(Security)
Symfony的安全系統(security system)是非常強大的,但在設定它時也可能令人困惑。在本大章中,你將學會如何一步步地設定程式的security,從配置防火牆(firewall)以及載入用戶,到拒絕存取和取到用戶物件。根據你的需求,有時在進行初始化設定時是痛苦的。然而一旦(配置)完成,Symfony的security系統在使用時,既靈活又(希望能夠)有樂趣。
由於有很多話要說,本章按幾個大部頭來組織:
#初始化
security.yml
的設定(authentication/驗證 );拒絕存取你的程式(authorization/授權 );
取得目前的User物件;
它們被細分為許多小塊內容(但仍然令人著迷),像是logging out 和
加密用戶密碼1)初始化security.yml的設定(Authentication/驗證) ¶
security系統在 app/config/security.yml 中進行配置。預設的配置是這樣的:
PHP:// app/config/security.php$container->loadFromExtension('security', array(
'providers' => array(
'in_memory' => array(
'memory' => null,
),
),
'firewalls' => array(
'dev' => array(
'pattern' => '^/(_(profiler|wdt)|css|images|js)/',
'security' => false,
),
'default' => array(
'anonymous' => null,
),
),));
XML:<!-- app/config/security.xml --><?xml version="1.0" encoding="UTF-8"?><srv:container xmlns="http://Symfony.com/schema/dic/security" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:srv="http://Symfony.com/schema/dic/services" xsi:schemaLocation="http://Symfony.com/schema/dic/services http://Symfony.com/schema/dic/services/services-1.0.xsd"> <config>
<provider name="in_memory">
<memory />
</provider> <firewall name="dev" pattern="^/(_(profiler|wdt)|css|images|js)/" security="false" /> <firewall name="default">
<anonymous />
</firewall>
</config></srv:container>
YAML:# app/config/security.ymlsecurity:
providers:
in_memory:
memory: ~
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
default:
anonymous: ~
firewalls
鍵是security配置的 核心
。
防火牆並不重要,它只是確保Symfony開發工具- 也就是居於/_profiler
和/_wdt
之下的那些URL將不會被你的security所阻止。你也可以針對請求中的其他細節來匹配一個請求(如 host主機)。閱讀 如何將防火牆限制在特定請求 以了解更多內容和例程。
A) 設定「如何讓使用者接受驗證」 ¶
防火牆的主要工作是去設定如何 讓你的使用者能夠被驗證。它們是否需要使用登入表單?還是HTTP basic驗證?抑或一個API token?還是上面所有這些?
讓我們從HTTP basic驗證開始(老舊的彈出框)展開。要啟動此功能,請添加 http_basic
到firewall下面:
PHP:// app/config/security.php$container->loadFromExtension('security', array( // ... 'firewalls' => array( // ... 'default' => array( 'anonymous' => null, 'http_basic' => null, ), ),));
XML:<!-- app/config/security.xml --><?xml version="1.0" encoding="UTF-8"?><srv:container xmlns="http://Symfony.com/schema/dic/security" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:srv="http://Symfony.com/schema/dic/services" xsi:schemaLocation="http://Symfony.com/schema/dic/services http://Symfony.com/schema/dic/services/services-1.0.xsd"> <config> <!-- ... --> <firewall name="default"> <anonymous /> <http-basic /> </firewall> </config></srv:container>
YAML:# app/config/security.ymlsecurity: # ... firewalls: # ... default: anonymous: ~ http_basic: ~
/admin
下建立一個新頁面 。例如,如果你使用annotations,建立下例程式碼:// src/AppBundle/Controller/DefaultController.php // ... use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;use Symfony\Bundle\FrameworkBundle\Controller\Controller;use Symfony\Component\HttpFoundation\Response; class DefaultController extends Controller{ /** * @Route("/admin") */ public function adminAction() { return new Response('<html><body>Admin page!</body></html>'); }}
接下來,在security.yml
中新增一個access_control
入口,以令用戶必先登入方可存取URL:
PHP:// app/config/security.php$container->loadFromExtension('security', array( // ... 'firewalls' => array( // ... 'default' => array( // ... ), ), 'access_control' => array( // require ROLE_ADMIN for /admin* array('path' => '^/admin', 'role' => 'ROLE_ADMIN'), ),));
XML:<!-- app/config/security.xml --><?xml version="1.0" encoding="UTF-8"?><srv:container xmlns="http://Symfony.com/schema/dic/security" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:srv="http://Symfony.com/schema/dic/services" xsi:schemaLocation="http://Symfony.com/schema/dic/services http://Symfony.com/schema/dic/services/services-1.0.xsd"> <config> <!-- ... --> <firewall name="default"> <!-- ... --> </firewall> <!-- require ROLE_ADMIN for /admin* --> <rule path="^/admin" role="ROLE_ADMIN" /> </config></srv:container>
YAML:# app/config/security.ymlsecurity: # ... firewalls: # ... default: # ... access_control: # require ROLE_ADMIN for /admin* - { path: ^/admin, roles: ROLE_ADMIN }
你將學到關於ROLE_ADMIN
以及後面的2 ) 拒絕存取, Roles和其他授權 小節中的「拒絕存取」等更多內容。
太好了,如果你去造訪/admin
,會看到HTTP Basic驗證的彈出式登入:
但是,你是以何種身分登入進來?用戶(資訊)又來自哪裡呢?
想要使用一個傳統的form表單?很好!參考 如何建立一個傳統的登入表單。還支援其他什麼(驗證)方式?參考 Configuration Reference 或 建立你自己的。
如果你的程式是透過Google,Facebook或Twitter等三方服務來完成登錄,請參閱 HWIOAuthBundle 社群bundle。
B) 設定「如何載入使用者」 ¶
當你在輸入使用者名稱時,Symfony就要從某個地方載入使用者的資訊。這就是所謂的“user provider”,由你來負責配置它。 Symfony有一個內建方式來 從資料庫載入使用者,但也可以 建立你自己的user provider。
最簡單的方式(但有許多限制),是設定Symfony從 security.yml
檔案裡直接載入寫死在其中的使用者。這被稱為“in memory” provider,但把它觀想為“in configuration” provider更合適些
PHP:// app/config/security.php$container->loadFromExtension('security', array( 'providers' => array( 'in_memory' => array( 'memory' => array( 'users' => array( 'ryan' => array( 'password' => 'ryanpass', 'roles' => 'ROLE_USER', ), 'admin' => array( 'password' => 'kitten', 'roles' => 'ROLE_ADMIN', ), ), ), ), ), // ...));
XML:<!-- app/config/security.xml --><?xml version="1.0" encoding="UTF-8"?><srv:container xmlns="http://Symfony.com/schema/dic/security" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:srv="http://Symfony.com/schema/dic/services" xsi:schemaLocation="http://Symfony.com/schema/dic/services http://Symfony.com/schema/dic/services/services-1.0.xsd"> <config> <provider name="in_memory"> <memory> <user name="ryan" password="ryanpass" roles="ROLE_USER" /> <user name="admin" password="kitten" roles="ROLE_ADMIN" /> </memory> </provider> <!-- ... --> </config></srv:container>
YAML:# app/config/security.ymlsecurity: providers: in_memory: memory: users: ryan: password: ryanpass roles: 'ROLE_USER' admin: password: kitten roles: 'ROLE_ADMIN' # ...
類似firewalls
,你可以擁有多個providers
,但你幾乎只需要一個。如果你確實 擁有多個,你可以在防火牆的provider
鍵(如provider:in_memory
)之下,設定「要使用哪一個一個”provider。
參考 如何使用多個User Providers 來了解multiple providers設定的全部細節。
試著以使用者名稱 admin
和密碼 kitten
來登入。你應該看到一個錯誤!
No encoder has been configured for account "Symfony\Component\Security\Core\User\User"
要修正此問題,新增一個encoders
健:
PHP:// app/config/security.php$container->loadFromExtension('security', array( // ... 'encoders' => array( 'Symfony\Component\Security\Core\User\User' => 'plaintext', ), // ...));
XML:<!-- app/config/security.xml --><?xml version="1.0" encoding="UTF-8"?><srv:container xmlns="http://Symfony.com/schema/dic/security" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:srv="http://Symfony.com/schema/dic/services" xsi:schemaLocation="http://Symfony.com/schema/dic/services http://Symfony.com/schema/dic/services/services-1.0.xsd"> <config> <!-- ... --> <encoder class="Symfony\Component\Security\Core\User\User" algorithm="plaintext" /> <!-- ... --> </config></srv:container>
YAML:app/config/security.ymlsecurity: # ... encoders: Symfony\Component\Security\Core\User\User: plaintext # ...
User providers載入使用者訊息,並將其置於一個User
物件中。如果你從資料庫載入使用者 或 從其他來源載入,你需要使用自訂的User類別。但當你使用「in memory」 provider時,它直接給了你一個 Symfony\Component\Security\Core\User\User
物件。
無論你使用什麼樣的User類,你都需要去告訴Symfony它們的密碼加密演算法是什麼。在本例中,密碼只是明文的文本,但很快,你要把它改成 bcrypt
。
如果你現在刷新,你就會登入進來! web調試工具列會告訴你,你是何人,你的roles(角色)是什麼:
#由於此URL需要的是ROLE_ADMIN
# ,如果你登入的是ryan
用戶,將被拒絕存取。更多內容參考後面的[URL受到保護的條件(access_control](#catalog9)。
從資料庫載入使用者 ¶
如果你想透過Doctrine Orm加載用戶,很容易!參考如何從資料庫(Entity Provider)載入Security系統之用戶 以了解全部細節。
C) 對用戶密碼進行加密 ¶
#不管使用者儲存在security.yml
裡,資料庫裡還是其他地方,你都需要去加密其密碼。堪用的最好演算法是bcrypt
:
PHP:// app/config/security.php$container->loadFromExtension('security', array( // ... 'encoders' => array( 'Symfony\Component\Security\Core\User\User' => array( 'algorithm' => 'bcrypt', 'cost' => 12, ) ), // ...));
XML:<!-- app/config/security.xml --><?xml version="1.0" encoding="UTF-8"?><srv:container xmlns="http://Symfony.com/schema/dic/security" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:srv="http://Symfony.com/schema/dic/services" xsi:schemaLocation="http://Symfony.com/schema/dic/services http://Symfony.com/schema/dic/services/services-1.0.xsd"> <config> <!-- ... --> <encoder class="Symfony\Component\Security\Core\User\User" algorithm="bcrypt" cost="12" /> <!-- ... --> </config></srv:container>
YAML:# app/config/security.ymlsecurity: # ... encoders: Symfony\Component\Security\Core\User\User: algorithm: bcrypt cost: 12
1 | $ php bin/console security:encode-password |