国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Yii修行之路 - Security 安全

AaronYuan / 2353人閱讀

摘要:認(rèn)證事件類在登錄和注銷流程引發(fā)一些事件。成功注銷后引發(fā)。提供兩種授權(quán)方法存取控制過濾器和基于角色的存取控制。允許已認(rèn)證用戶執(zhí)行操作。指定一個回調(diào)函數(shù)用于判定該規(guī)則是否滿足條件。

簡述

在程序開發(fā)過程中,往往都不能忽視安全問題,無論你的框架有多么完美,都會有破綻,所以完善自己的系統(tǒng),從程序開發(fā)的安全角度去思考問題,把一切潛在的危機扼殺在搖籃中。

認(rèn)證(Authentication)

認(rèn)證是鑒定用戶身份的過程。

它通常使用一個標(biāo)識符 (如用戶名或電子郵件地址)和一個加密令牌(比如密碼或者存取令牌)來 鑒別用戶身份。

認(rèn)證是登錄功能的基礎(chǔ)。
Yii提供了一個認(rèn)證框架,它連接了不同的組件以支持登錄。欲使用這個框架, 你主要需要做以下工作:

設(shè)置用戶組件 yiiwebUser ;

創(chuàng)建一個類實現(xiàn) yiiwebIdentityInterface 接口。

配置 yiiwebUser

用戶組件 yiiwebUser 用來管理用戶的認(rèn)證狀態(tài)。

這需要你 指定一個含有實際認(rèn)證邏輯的認(rèn)證類 yiiwebUser::identityClass。

在以下web應(yīng)用的配置項中,將用戶用戶組件 yiiwebUser 的 認(rèn)證類 yiiwebUser::identityClass 配置成 模型類 appmodelsUser。

return [
    "components" => [
        "user" => [
            "identityClass" => "appmodelsUser",
        ],
    ],
];
認(rèn)證接口 yiiwebIdentityInterface 的實現(xiàn)

認(rèn)證類 yiiwebUser::identityClass 必須實現(xiàn)包含以下方法的 認(rèn)證接口 yiiwebIdentityInterface:

yiiwebIdentityInterface::findIdentity():根據(jù)指定的用戶ID查找 認(rèn)證模型類的實例,當(dāng)你需要使用session來維持登錄狀態(tài)的時候會用到這個方法。

yiiwebIdentityInterface::findIdentityByAccessToken():根據(jù)指定的存取令牌查找 認(rèn)證模型類的實例,該方法用于 通過單個加密令牌認(rèn)證用戶的時候(比如無狀態(tài)的RESTful應(yīng)用)。

yiiwebIdentityInterface::getId():獲取該認(rèn)證實例表示的用戶的ID。

yiiwebIdentityInterface::getAuthKey():獲取基于 cookie 登錄時使用的認(rèn)證密鑰。 認(rèn)證密鑰儲存在 cookie 里并且將來會與服務(wù)端的版本進行比較以確保 cookie的有效性。

yiiwebIdentityInterface::validateAuthKey() :是基于 cookie 登錄密鑰的 驗證的邏輯的實現(xiàn)。

用不到的方法可以空著,例如,你的項目只是一個 無狀態(tài)的 RESTful 應(yīng)用,只需實現(xiàn) yiiwebIdentityInterface::findIdentityByAccessToken() 和 yiiwebIdentityInterface::getId() ,其他的方法的函數(shù)體留空即可。

下面的例子是一個通過結(jié)合了 user 數(shù)據(jù)表的 AR 模型 Active Record 實現(xiàn)的一個認(rèn)證類 yiiwebUser::identityClass。

 $token]);
    }

    /**
     * @return int|string 當(dāng)前用戶ID
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * @return string 當(dāng)前用戶的(cookie)認(rèn)證密鑰
     */
    public function getAuthKey()
    {
        return $this->auth_key;
    }

    /**
     * @param string $authKey
     * @return boolean if auth key is valid for current user
     */
    public function validateAuthKey($authKey)
    {
        return $this->getAuthKey() === $authKey;
    }
}

如上所述,如果你的應(yīng)用利用 cookie 登錄, 你只需要實現(xiàn) getAuthKey() 和 validateAuthKey() 方法。這樣的話,你可以使用下面的代碼在 user 表中生成和存儲每個用戶的認(rèn)證密鑰。

class User extends ActiveRecord implements IdentityInterface{
    ......

    public function beforeSave($insert)
    {
        if (parent::beforeSave($insert)) {
            if ($this->isNewRecord) {
                $this->auth_key = Yii::$app->security->generateRandomString();
            }
            return true;
        }
        return false;
    }
}

注意:不要混淆 user 認(rèn)證類和用戶組件 yiiwebUser。前者是實現(xiàn) 認(rèn)證邏輯的類,通常用關(guān)聯(lián)了 持久性存儲的用戶信息的AR模型 Active Record 實現(xiàn)。后者是負(fù)責(zé)管理用戶認(rèn)證狀態(tài)的 應(yīng)用組件。

使用用戶組件 yiiwebUser

在 user 應(yīng)用組件方面,你主要用到 yiiwebUser 。

你可以使用表達式 Yii::$app->user->identity 檢測當(dāng)前用戶身份。它返回 一個表示當(dāng)前登錄用戶的認(rèn)證類 yiiwebUser::identityClass 的實例, 未認(rèn)證用戶(游客)則返回 null。

下面的代碼展示了如何從 yiiwebUser 獲取其他認(rèn)證相關(guān)信息:

// 當(dāng)前用戶的身份實例。未認(rèn)證用戶則為 Null 。
$identity = Yii::$app->user->identity;

// 當(dāng)前用戶的ID。 未認(rèn)證用戶則為 Null 。
$id = Yii::$app->user->id;

// 判斷當(dāng)前用戶是否是游客(未認(rèn)證的)
$isGuest = Yii::$app->user->isGuest;

你可以使用下面的代碼登錄用戶:

// 使用指定用戶名獲取用戶身份實例。
// 請注意,如果需要的話您可能要檢驗密碼
$identity = User::findOne(["username" => $username]);

// 登錄用戶
Yii::$app->user->login($identity);
yiiwebUser::login() 方法將當(dāng)前用戶的身份登記到 yiiwebUser。

如果 session 設(shè)置為 yiiwebUser::enableSession,則使用 session 記錄用戶身份,用戶的 認(rèn)證狀態(tài)將在整個會話中得以維持。

如果開啟自動登錄 yiiwebUser::enableAutoLogin 則基于 cookie 登錄(如:記住登錄狀態(tài)),它將使用 cookie 保存用戶身份,這樣 只要 cookie 有效就可以恢復(fù)登錄狀態(tài)。

為了使用 cookie 登錄,你需要在應(yīng)用配置文件中將 yiiwebUser::enableAutoLogin 設(shè)為 true。
你還需要在 yiiwebUser::login() 方法中 傳遞有效期(記住登錄狀態(tài)的時長)參數(shù)。

注銷用戶:

Yii::$app->user->logout();

請注意,啟用 session 時注銷用戶才有意義。該方法將從內(nèi)存和 session 中 同時清理用戶認(rèn)證狀態(tài)。

默認(rèn)情況下,它還會注銷所有的 用戶會話數(shù)據(jù)。

如果你希望保留這些會話數(shù)據(jù),可以換成 Yii::$app->user->logout(false) 。
認(rèn)證事件

yiiwebUser 類在登錄和注銷流程引發(fā)一些事件。

    1、yiiwebUser::EVENT_BEFORE_LOGIN:在登錄 yiiwebUser::login() 時引發(fā)。 
    如果事件句柄將事件對象的 yiiwebUserEvent::isValid 屬性設(shè)為 false, 登錄流程將會被取消。
    
    2、yiiwebUser::EVENT_AFTER_LOGIN:登錄成功后引發(fā)。
    
    3、yiiwebUser::EVENT_BEFORE_LOGOUT:注銷 yiiwebUser::logout() 前引發(fā)。 
    如果事件句柄將事件對象的 yiiwebUserEvent::isValid 屬性設(shè)為 false, 注銷流程將會被取消。
    
    4、yiiwebUser::EVENT_AFTER_LOGOUT:成功注銷后引發(fā)。

你可以通過響應(yīng)這些事件來實現(xiàn)一些類似登錄統(tǒng)計、在線人數(shù)統(tǒng)計的功能。例如, 在登錄后 yiiwebUser::EVENT_AFTER_LOGIN 的處理程序,你可以將用戶的登錄時間和IP記錄到 user 表中。

授權(quán)(Authorization)

授權(quán)是指驗證用戶是否允許做某件事的過程。

Yii提供兩種授權(quán)方法: 存取控制過濾器(ACF)和基于角色的存取控制(RBAC)。

存取控制過濾器

存取控制過濾器(ACF)是一種通過 yiifiltersAccessControl 類來實現(xiàn)的簡單授權(quán)方法, 非常適用于僅需要簡單的存取控制的應(yīng)用。

正如其名稱所指,ACF 是一個種行動(action)過濾器 filter,可在控制器或者模塊中使用。當(dāng)一個用戶請求一個 action 時, ACF會檢查 yiifiltersAccessControl::rules 列表,判斷該用戶是否允許執(zhí) 行所請求的action。(譯者注: action 在本文中視情況翻譯為行動、操作、方法等)

下述代碼展示如何在 site 控制器中使用 ACF:

use yiiwebController;
use yiifiltersAccessControl;

class SiteController extends Controller{
    public function behaviors()
    {
        return [
            "access" => [
                "class" => AccessControl::className(),
                "only" => ["login", "logout", "signup"],
                "rules" => [
                    [
                        "allow" => true,
                        "actions" => ["login", "signup"],
                        "roles" => ["?"],
                    ],
                    [
                        "allow" => true,
                        "actions" => ["logout"],
                        "roles" => ["@"],
                    ],
                ],
            ],
        ];
    }
    // ...
}

上面的代碼中 ACF 以行為 (behavior) 的形式附加到 site 控制器。 這就是很典型的使用行動過濾器的方法。

only 選項指明 ACF 應(yīng)當(dāng)只 對 login, logout 和 signup 方法起作用。所有其它的 site 控制器中的方法不受存取控制的限制。

rules 選項列出了 yiifiltersAccessRule,解讀如下:

允許所有訪客(還未經(jīng)認(rèn)證的用戶)執(zhí)行 login 和 signup 操作。 roles 選項包含的問號 ? 是一個特殊的標(biāo)識,代表”訪客用戶”。

允許已認(rèn)證用戶執(zhí)行 logout 操作。@是另一個特殊標(biāo)識, 代表”已認(rèn)證用戶”。

ACF 自上向下逐一檢查存取規(guī)則,直到找到一個與當(dāng)前 欲執(zhí)行的操作相符的規(guī)則。 然后該匹配規(guī)則中的 allow 選項的值用于判定該用戶是否獲得授權(quán)。如果沒有找到匹配的規(guī)則, 意味著該用戶沒有獲得授權(quán)。(譯者注: only 中沒有列出的操作,將無條件獲得授權(quán))

當(dāng) ACF 判定一個用戶沒有獲得執(zhí)行當(dāng)前操作的授權(quán)時,它的默認(rèn)處理是:

如果該用戶是訪客,將調(diào)用 yiiwebUser::loginRequired() 將用戶的瀏覽器重定向到登錄頁面。

如果該用戶是已認(rèn)證用戶,將拋出一個 yiiwebForbiddenHttpException 異常。

你可以通過配置 yiifiltersAccessControl::denyCallback 屬性定制該行為:

[
    "class" => AccessControl::className(),
    ...
    "denyCallback" => function ($rule, $action) {
        throw new Exception("You are not allowed to access this page");
    }
]

yiifiltersAccessRule 支持很多的選項。

下列是所支持選項的總覽:你可以派生 yiifiltersAccessRule 來創(chuàng)建自定義的存取規(guī)則類。

    * yiifiltersAccessRule::allow: 指定該規(guī)則是 "允許" 還是 "拒絕" 。(譯者注:true是允許,false是拒絕)

    * yiifiltersAccessRule::actions:指定該規(guī)則用于匹配哪些操作。 它的值應(yīng)該是操作方法的ID數(shù)組。匹配比較是大小寫敏感的。如果該選項為空,或者不使用該選項, 意味著當(dāng)前規(guī)則適用于所有的操作。

    1、yiifiltersAccessRule::controllers:指定該規(guī)則用于匹配哪些控制器。 它的值應(yīng)為控制器ID數(shù)組。匹配比較是大小寫敏感的。如果該選項為空,或者不使用該選項, 則意味著當(dāng)前規(guī)則適用于所有的操作。(譯者注:這個選項一般是在控制器的自定義父類中使用才有意義)

    2、yiifiltersAccessRule::roles:指定該規(guī)則用于匹配哪些用戶角色。 系統(tǒng)自帶兩個特殊的角色,通過 yiiwebUser::isGuest 來判斷:

        * ?: 用于匹配訪客用戶 (未經(jīng)認(rèn)證)
        * @: 用于匹配已認(rèn)證用戶

    3、使用其他角色名時,將觸發(fā)調(diào)用 yiiwebUser::can(),這時要求 RBAC 的支持 (在下一節(jié)中闡述)。 如果該選項為空或者不使用該選項,意味著該規(guī)則適用于所有角色。

    4、yiifiltersAccessRule::ips:指定該規(guī)則用于匹配哪些 yiiwebRequest::userIP 。 IP 地址可在其末尾包含通配符 * 以匹配一批前綴相同的IP地址。 例如,192.168.* 匹配所有 192.168. 段的IP地址。 如果該選項為空或者不使用該選項,意味著該規(guī)則適用于所有角色。

    5、yiifiltersAccessRule::verbs:指定該規(guī)則用于匹配哪種請求方法(例如GET,POST)。 這里的匹配大小寫不敏感。

    6、yiifiltersAccessRule::matchCallback:指定一個PHP回調(diào)函數(shù)用于 判定該規(guī)則是否滿足條件。(譯者注:此處的回調(diào)函數(shù)是匿名函數(shù))

    7、yiifiltersAccessRule::denyCallback: 指定一個PHP回調(diào)函數(shù), 當(dāng)這個規(guī)則不滿足條件時該函數(shù)會被調(diào)用。(譯者注:此處的回調(diào)函數(shù)是匿名函數(shù))

以下例子展示了如何使用 matchCallback 選項, 可使你設(shè)計任意的訪問權(quán)限檢查邏輯:

use yiifiltersAccessControl;

class SiteController extends Controller{
    public function behaviors()
    {
        return [
            "access" => [
                "class" => AccessControl::className(),
                "only" => ["special-callback"],
                "rules" => [
                    [
                        "actions" => ["special-callback"],
                        "allow" => true,
                        "matchCallback" => function ($rule, $action) {
                            return date("d-m") === "31-10";
                        }
                    ],
                ],
            ],
        ];
    }

    // 匹配的回調(diào)函數(shù)被調(diào)用了!這個頁面只有每年的10月31號能訪問(譯者注:原文在這里說該方法是回調(diào)函數(shù)不確切,讀者不要和 `matchCallback` 的值即匿名的回調(diào)函數(shù)混淆理解)。
    public function actionSpecialCallback()
    {
        return $this->render("happy-halloween");
    }
}
基于角色的存取控制 (RBAC)

基于角色的存取控制 (RBAC) 提供了一個簡單而強大的集中式存取控制機制。

Yii 實現(xiàn)了通用的分層的 RBAC,遵循的模型是 NIST RBAC model. 它通過 yiirbacManagerInterface application component 提供 RBAC 功能。
使用 RBAC 涉及到兩部分工作。第一部分是建立授權(quán)數(shù)據(jù), 而第二部分是使用這些授權(quán)數(shù)據(jù)在需要的地方執(zhí)行檢查。
為方便后面的講述,這里先介紹一些 RBAC 的基本概念。

基本概念

角色是 權(quán)限 的集合 (例如:建貼、改貼)。一個角色 可以指派給一個或者多個用戶。要檢查某用戶是否有一個特定的權(quán)限, 系統(tǒng)會檢查該包含該權(quán)限的角色是否指派給了該用戶。

可以用一個規(guī)則 rule 與一個角色或者權(quán)限關(guān)聯(lián)。一個規(guī)則用一段代碼代表, 規(guī)則的執(zhí)行是在檢查一個用戶是否滿足這個角色或者權(quán)限時進行的。

例如,"改帖" 的權(quán)限 可以使用一個檢查該用戶是否是帖子的創(chuàng)建者的規(guī)則。權(quán)限檢查中,如果該用戶 不是帖子創(chuàng)建者,那么他(她)將被認(rèn)為不具有 "改帖"的權(quán)限。

角色和權(quán)限都可以按層次組織。特定情況下,一個角色可能由其他角色或權(quán)限構(gòu)成, 而權(quán)限又由其他的權(quán)限構(gòu)成。

Yii 實現(xiàn)了所謂的 局部順序 的層次結(jié)構(gòu),包含更多的特定的 樹 的層次。 一個角色可以包含一個權(quán)限,反之則不行。(譯者注:可理解為角色在上方,權(quán)限在下方,從上到下如果碰到權(quán)限那么再往下不能出現(xiàn)角色)

配置 RBAC

在開始定義授權(quán)數(shù)據(jù)和執(zhí)行存取檢查之前,需要先配置應(yīng)用組件 yiibaseApplication::authManager 。

Yii 提供了兩套授權(quán)管理器: yiirbacPhpManager 和 yiirbacDbManager。前者使用 PHP 腳本存放授權(quán)數(shù)據(jù), 而后者使用數(shù)據(jù)庫存放授權(quán)數(shù)據(jù)。 如果你的應(yīng)用不要求大量的動態(tài)角色和權(quán)限管理, 你可以考慮使用前者。

使用 PhpManager
以下代碼展示使用 yiirbacPhpManager 時如何在應(yīng)用配置文件中配置 authManager:

return [
    // ...
    "components" => [
        "authManager" => [
            "class" => "yii
bacPhpManager",
        ],
        // ...
    ],
];

現(xiàn)在可以通過 Yii::$app->authManager 訪問 authManager 。
yiirbacPhpManager 默認(rèn)將 RBAC 數(shù)據(jù)保存在 @app/rbac 目錄下的文件中。 如果權(quán)限層次數(shù)據(jù)在運行時會被修改,需確保WEB服務(wù)器進程對該目錄和其中的文件有寫權(quán)限。

使用 DbManager

以下代碼展示使用 yiirbacDbManager 時如何在應(yīng)用配置文件中配置 authManager:
return [

// ...
"components" => [
    "authManager" => [
        "class" => "yii
bacDbManager",
    ],
    // ...
],

];
DbManager 使用4個數(shù)據(jù)庫表存放它的數(shù)據(jù):

yiirbacDbManager::$itemTable: 該表存放授權(quán)條目(譯者注:即角色和權(quán)限)。默認(rèn)表名為 "auth_item" 。

yiirbacDbManager::$itemChildTable: 該表存放授權(quán)條目的層次關(guān)系。默認(rèn)表名為 "auth_item_child"。

yiirbacDbManager::$assignmentTable: 該表存放授權(quán)條目對用戶的指派情況。默認(rèn)表名為 "auth_assignment"。

yiirbacDbManager::$ruleTable: 該表存放規(guī)則。默認(rèn)表名為 "auth_rule"。

繼續(xù)之前,你需要在數(shù)據(jù)庫中創(chuàng)建這些表。

你可以使用存放在 @yii/rbac/migrations 目錄中的數(shù)據(jù)庫遷移文件來做這件事(譯者注:根據(jù)本人經(jīng)驗,最好是將授權(quán)數(shù)據(jù)初始化命令也寫到這個 RBAC 數(shù)據(jù)庫遷移文件中):

yii migrate --migrationPath=@yii/rbac/migrations

現(xiàn)在可以通過 Yii::$app->authManager 訪問 authManager 。

建立授權(quán)數(shù)據(jù)
所有授權(quán)數(shù)據(jù)相關(guān)的任務(wù)如下:

定義角色和權(quán)限;

建立角色和權(quán)限的關(guān)系;

定義規(guī)則;

將規(guī)則與角色和權(quán)限作關(guān)聯(lián);

指派角色給用戶。

根據(jù)授權(quán)的彈性需求,上述任務(wù)可用不同的方法完成。

如果你的權(quán)限層次結(jié)構(gòu)不會發(fā)生改變,而且你的用戶數(shù)是恒定的,你可以通過 authManager 提供的 API 創(chuàng)建一個 控制臺命令 一次性初始化授權(quán)數(shù)據(jù):

authManager;

        // 添加 "createPost" 權(quán)限
        $createPost = $auth->createPermission("createPost");
        $createPost->description = "Create a post";
        $auth->add($createPost);

        // 添加 "updatePost" 權(quán)限
        $updatePost = $auth->createPermission("updatePost");
        $updatePost->description = "Update post";
        $auth->add($updatePost);

        // 添加 "author" 角色并賦予 "createPost" 權(quán)限
        $author = $auth->createRole("author");
        $auth->add($author);
        $auth->addChild($author, $createPost);

        // 添加 "admin" 角色并賦予 "updatePost" 
        // 和 "author" 權(quán)限
        $admin = $auth->createRole("admin");
        $auth->add($admin);
        $auth->addChild($admin, $updatePost);
        $auth->addChild($admin, $author);

        // 為用戶指派角色。其中 1 和 2 是由 IdentityInterface::getId() 返回的id (譯者注:user表的id)
        // 通常在你的 User 模型中實現(xiàn)這個函數(shù)。
        $auth->assign($author, 2);
        $auth->assign($admin, 1);
    }
}

在用 yii rbac/init 執(zhí)行了這個命令后,我們將得到下圖所示的層次結(jié)構(gòu):

作者可創(chuàng)建新貼,管理員可編輯帖子以及所有作者可做的事情。

如果你的應(yīng)用允許用戶注冊,你需要在注冊時給新用戶指派一次角色。

例如, 在高級項目模板中,要讓所有注冊用戶成為作者,你需要如下例所示修改 frontendmodelsSignupForm::signup() 方法:

public function signup(){
    if ($this->validate()) {
        $user = new User();
        $user->username = $this->username;
        $user->email = $this->email;
        $user->setPassword($this->password);
        $user->generateAuthKey();
        $user->save(false);

        // 要添加以下三行代碼:
        $auth = Yii::$app->authManager;
        $authorRole = $auth->getRole("author");
        $auth->assign($authorRole, $user->getId());

        return $user;
    }

    return null;
}

對于有動態(tài)更改授權(quán)數(shù)據(jù)的復(fù)雜存取控制需求的,你可能需要使用 authManager 提供的 API 的開發(fā)用戶界面(例如:管理面板)。

使用規(guī)則 (Rules)

如前所述,規(guī)則給角色和權(quán)限增加額外的約束條件。規(guī)則是 yiirbacRule 的派生類。 它需要實現(xiàn) yiirbacRule::execute() 方法。

在之前我們創(chuàng)建的層次結(jié)構(gòu)中,作者不能編輯自己的帖子,我們來修正這個問題。 首先我們需要一個規(guī)則來認(rèn)證當(dāng)前用戶是帖子的作者:

namespace app
bac;

use yii
bacRule;

/**
 * 檢查 authorID 是否和通過參數(shù)傳進來的 user 參數(shù)相符
 */class AuthorRule extends Rule{
    public $name = "isAuthor";

    /**
     * @param string|integer $user 用戶 ID.
     * @param Item $item 該規(guī)則相關(guān)的角色或者權(quán)限
     * @param array $params 傳給 ManagerInterface::checkAccess() 的參數(shù)
     * @return boolean 代表該規(guī)則相關(guān)的角色或者權(quán)限是否被允許
     */
    public function execute($user, $item, $params)
    {
        return isset($params["post"]) ? $params["post"]->createdBy == $user : false;
    }
}

上述規(guī)則檢查 post 是否是 $user 創(chuàng)建的。我們還要在之前的命令中 創(chuàng)建一個特別的權(quán)限 updateOwnPost :

$auth = Yii::$app->authManager;

// 添加規(guī)則
$rule = new app
bacAuthorRule;$auth->add($rule);

// 添加 "updateOwnPost" 權(quán)限并與規(guī)則關(guān)聯(lián)
$updateOwnPost = $auth->createPermission("updateOwnPost");
$updateOwnPost->description = "Update own post";
$updateOwnPost->ruleName = $rule->name;
$auth->add($updateOwnPost);

// "updateOwnPost" 權(quán)限將由 "updatePost" 權(quán)限使用
$auth->addChild($updateOwnPost, $updatePost);

// 允許 "author" 更新自己的帖子
$auth->addChild($author, $updateOwnPost);
使用默認(rèn)角色

所謂默認(rèn)角色就是 隱式 地指派給 所有 用戶的角色。不需要調(diào)用 yiirbacManagerInterface::assign() 方法做顯示指派,并且授權(quán)數(shù)據(jù)中不包含指派信息。

默認(rèn)角色通常與一個規(guī)則關(guān)聯(lián),用以檢查該角色是否符合被檢查的用戶。

默認(rèn)角色常常用于已經(jīng)確立了一些角色的指派關(guān)系的應(yīng)用(譯者注:指派關(guān)系指的是應(yīng)用業(yè)務(wù)邏輯層面, 并非指授權(quán)數(shù)據(jù)的結(jié)構(gòu))。比如,一個應(yīng)用的 user 表中有一個 group 字段,代表用戶屬于哪個特權(quán)組。 如果每個特權(quán)組可以映射到 RBAC 的角色,你就可以采用默認(rèn)角色自動地為每個用戶指派一個 RBAC 角色。 讓我們用一個例子展示如何做到這一點。

假設(shè)在 user 表中,你有一個 group 字段,用 1 代表管理員組,用 2 表示作者組。 你規(guī)劃兩個 RBAC 角色 admin 和 author 分別對應(yīng)這兩個組的權(quán)限。 你可以這樣設(shè)置 RBAC 數(shù)據(jù),

namespace app
bac;

use Yii;
use yii
bacRule;

/**
 * 檢查是否匹配用戶的組
 */class UserGroupRule extends Rule{
    public $name = "userGroup";

    public function execute($user, $item, $params)
    {
        if (!Yii::$app->user->isGuest) {
            $group = Yii::$app->user->identity->group;
            if ($item->name === "admin") {
                return $group == 1;
            } elseif ($item->name === "author") {
                return $group == 1 || $group == 2;
            }
        }
        return false;
    }
}

$auth = Yii::$app->authManager;

$rule = new app
bacUserGroupRule;
$auth->add($rule);

$author = $auth->createRole("author");
$author->ruleName = $rule->name;
$auth->add($author);
// ... 添加$author角色的子項部分代碼 ... (譯者注:省略部分參照之前的控制臺命令)

$admin = $auth->createRole("admin");
$admin->ruleName = $rule->name;
$auth->add($admin);
$auth->addChild($admin, $author);
// ... 添加$admin角色的子項部分代碼 ... (譯者注:省略部分參照之前的控制臺命令)

注意,在上述代碼中,因為 "author" 作為 "admin" 的子角色,當(dāng)你實現(xiàn)這個規(guī)則的 execute() 方法時, 你也需要遵從這個層次結(jié)構(gòu)。

這就是為何當(dāng)角色名為 "author" 的情況下(譯者注:$item->name就是角色名), execute() 方法在組為 1 或者 2 時均要返回 true (意思是用戶屬于 "admin" 或者 "author" 組 )。

接下來,在配置 authManager 時指定 yiirbacBaseManager::$defaultRoles 選項(譯者注:在應(yīng)用配置文件中的組件部分配置):

return [
    // ...
    "components" => [
        "authManager" => [
            "class" => "yii
bacPhpManager",
            "defaultRoles" => ["admin", "author"],
        ],
        // ...
    ],
];
現(xiàn)在如果你執(zhí)行一個存取權(quán)限檢查, 判定該規(guī)則時, admin 和 author 兩個角色都將會檢查。如果規(guī)則返回 true ,意思是角色符合當(dāng)前用戶。基于上述規(guī)則 的實現(xiàn),意味著如果某用戶的 group 值為 1 , admin 角色將賦予該用戶, 如果 group 值是 2 則將賦予author 角色。
處理密碼(Passwords)

好的安全策略對任何應(yīng)用的健康和成功極其重要。

不幸的是,許多開發(fā)者在遇到安全問題時,因為認(rèn)識不夠或者實現(xiàn)起來比較麻煩,都不是很注意細(xì)節(jié)。

為了讓你的 Yii 應(yīng)用程序盡可能的安全, Yii 囊括了一些卓越并簡單易用的安全特性。

密碼的哈希與驗證

大部分開發(fā)者知道密碼不能以明文形式存儲,但是許多開發(fā)者仍認(rèn)為使用 md5 或者 sha1 來哈希化密碼是安全的。

一度,使用上述的哈希算法是足夠安全的,但是,現(xiàn)代硬件的發(fā)展使得短時間內(nèi)暴力破解上述算法生成的哈希串成為可能。

為了即使在最糟糕的情況下(你的應(yīng)用程序被破解了)也能給用戶密碼提供增強的安全性,你需要使用一個能夠?qū)贡┝ζ平夤舻墓K惴ǎ壳白詈玫倪x擇是 bcrypt。

在 PHP 中,你可以通過 crypt 函數(shù) 生成 bcrypt 哈希。Yii 提供了兩個幫助函數(shù)以讓使用crypt 來進行安全的哈希密碼生成和驗證更加容易。

當(dāng)一個用戶為第一次使用,提供了一個密碼時(比如:注冊時),密碼就需要被哈希化。
$hash = Yii::$app->getSecurity()->generatePasswordHash($password);

哈希串可以被關(guān)聯(lián)到對應(yīng)的模型屬性,這樣,它可以被存儲到數(shù)據(jù)庫中以備將來使用。

當(dāng)一個用戶嘗試登錄時,表單提交的密碼需要使用之前的存儲的哈希串來驗證:

if (Yii::$app->getSecurity()->validatePassword($password, $hash)) {
    // all good, logging user in
} else {
    // wrong password
}
生成偽隨機數(shù)

偽隨機數(shù)據(jù)在許多場景下都非常有用。

比如當(dāng)通過郵件重置密碼時,你需要生成一個令牌,將其保存到數(shù)據(jù)庫中,并通過郵件發(fā)送到終端用戶那里以讓其證明其對某個賬號的所有權(quán)。

這個令牌的唯一性和難猜解性非常重要,否則,就存在攻擊者猜解令牌,并重置用戶的密碼的可能性。

Yii 安全助手使得生成偽隨機數(shù)據(jù)非常簡單:

$key = Yii::$app->getSecurity()->generateRandomString();

注意,你需要安裝有 openssl 擴展,以生成密碼的安全隨機數(shù)據(jù)。

加密與解密

Yii 提供了方便的幫助函數(shù)來讓你用一個安全秘鑰來加密解密數(shù)據(jù)。數(shù)據(jù)通過加密函數(shù)進行傳輸,這樣只有擁有安全秘鑰的人才能解密。

比如,我們需要存儲一些信息到我們的數(shù)據(jù)庫中,但是,我們需要保證只有擁有安全秘鑰的人才能看到它(即使應(yīng)用的數(shù)據(jù)庫泄露)

// $data and $secretKey are obtained from the form
$encryptedData = Yii::$app->getSecurity()->encryptByPassword($data, $secretKey);

// store $encryptedData to database

隨后,當(dāng)用戶需要讀取數(shù)據(jù)時:

// $secretKey is obtained from user input, $encryptedData is from the database
$data = Yii::$app->getSecurity()->decryptByPassword($encryptedData, $secretKey);
校驗數(shù)據(jù)完整性

有時,你需要驗證你的數(shù)據(jù)沒有第三方篡改或者使用某種方式破壞了。Yii 通過兩個幫助函數(shù),提供了一個簡單的方式來進行數(shù)據(jù)的完整性校驗。

首先,將由安全秘鑰和數(shù)據(jù)生成的哈希串前綴到數(shù)據(jù)上。

// $secretKey our application or user secret, $genuineData obtained from a reliable source
$data = Yii::$app->getSecurity()->hashData($genuineData, $secretKey);

驗證數(shù)據(jù)完整性是否被破壞了。

// $secretKey our application or user secret, $data obtained from an unreliable source
$data = Yii::$app->getSecurity()->validateData($data, $secretKey);

你同樣可以給控制器或者 action 設(shè)置它的 enableCsrfValidation 屬性來多帶帶禁用 CSRF 驗證。

namespace appcontrollers;

use yiiwebController;

class SiteController extends Controller{
    public $enableCsrfValidation = false;

    public function actionIndex()
    {
        // CSRF validation will not be applied to this and other actions
    }

}

為了給某個定制的 action 關(guān)閉 CSRF 驗證,你可以:

namespace appcontrollers;

use yiiwebController;

class SiteController extends Controller{
    public function beforeAction($action)
    {
        // ...set `$this->enableCsrfValidation` here based on some conditions...
        // call parent method that will check CSRF if such property is true.
        return parent::beforeAction($action);
    }
}
一些最佳安全實踐(Best Practices)

基本準(zhǔn)則無論是開發(fā)何種應(yīng)用程序,我們都有兩條基本的安全準(zhǔn)則:

過濾輸入

轉(zhuǎn)義輸出

過濾輸入

過濾輸入的意思是,用戶輸入不應(yīng)該認(rèn)為是安全的,你需要總是驗證你獲得的輸入值是在允許范圍內(nèi)。

比如,我們假設(shè) sorting 只能指定為 title, created_at 和 status 三個值,然后,這個值是由用戶輸入提供的,那么,最好在我們接收參數(shù)的時候,檢查一下這個值是否是指定的范圍。

對于基本的 PHP 而言,上述做法類似如下:

$sortBy = $_GET["sort"];
if (!in_array($sortBy, ["title", "created_at", "status"])) {
    throw new Exception("Invalid sort value.");
}

在 Yii 中,很大可能性,你會使用 表單校驗器 來執(zhí)行類似的檢查。

轉(zhuǎn)義輸出

轉(zhuǎn)義輸出的意思是,根據(jù)我們使用數(shù)據(jù)的上下文環(huán)境,數(shù)據(jù)需要被轉(zhuǎn)義。

比如:在 HTML 上下文,你需要轉(zhuǎn)義 <,> 之類的特殊字符。在 JavaScript 或者 SQL 中,也有其他的特殊含義的字符串需要被轉(zhuǎn)義。

由于手動的給所用的輸出轉(zhuǎn)義容易出錯,Yii 提供了大量的工具來在不同的上下文執(zhí)行轉(zhuǎn)義。

避免 SQL 注入

SQL 注入發(fā)生在查詢語句是由連接未轉(zhuǎn)義的字符串生成的場景,比如:

$username = $_GET["username"];
$sql = "SELECT * FROM user WHERE username = "$username"";

除了提供正確的用戶名外,攻擊者可以給你的應(yīng)用程序輸入類似 "; DROP TABLE user; --` 的語句。 這將會導(dǎo)致生成如下的 SQL :

SELECT * FROM user WHERE username = ""; DROP TABLE user; --"

這是一個合法的查詢語句,并將會執(zhí)行以空的用戶名搜索用戶操作,然后,刪除 user 表。這極有可能導(dǎo)致網(wǎng)站出差,數(shù)據(jù)丟失。(你是否進行了規(guī)律的數(shù)據(jù)備份?)

在 Yii 中,大部分的數(shù)據(jù)查詢是通過 Active Record 進行的,而其是完全使用 PDO 預(yù)處理語句執(zhí)行 SQL 查詢的。在預(yù)處理語句中,上述示例中,構(gòu)造 SQL 查詢的場景是不可能發(fā)生的。

有時,你仍需要使用 raw queries 或者 query builder。在這種情況下,你應(yīng)該使用安全的方式傳遞參數(shù)。如果數(shù)據(jù)是提供給表列的值,最好使用預(yù)處理語句:

// query builder
$userIDs = (new Query())
    ->select("id")
    ->from("user")
    ->where("status=:status", [":status" => $status])
    ->all();

// DAO
$userIDs = $connection
    ->createCommand("SELECT id FROM user where status=:status")
    ->bindValues([":status" => $status])
    ->queryColumn();

如果數(shù)據(jù)是用于指定列的名字,或者表的名字,最好的方式是只允許預(yù)定義的枚舉值。

function actionList($orderBy = null){
    if (!in_array($orderBy, ["name", "status"])) {
        throw new BadRequestHttpException("Only name and status are allowed to order by.")
    }

    // ...
}

如果上述方法不行,表名或者列名應(yīng)該被轉(zhuǎn)義。 Yii 針對這種轉(zhuǎn)義提供了一個特殊的語法,這樣可以在所有支持的數(shù)據(jù)庫都使用一套方案。

$sql = "SELECT COUNT($column) FROM {{table}}";
$rowCount = $connection->createCommand($sql)->queryScalar();
防止 XSS 攻擊

XSS 或者跨站腳本發(fā)生在輸出 HTML 到瀏覽器時,輸出內(nèi)容沒有正確的轉(zhuǎn)義。

例如,如果用戶可以輸入其名稱,那么他輸入 而非其名字 Alexander,所有輸出沒有轉(zhuǎn)義直接輸出用戶名的頁面都會執(zhí)行 JavaScript 代碼 alert("Hello!");,這會導(dǎo)致瀏覽器頁面上出現(xiàn)一個警告彈出框。

就具體的站點而言,除了這種無意義的警告輸出外,這樣的腳本可以以你的名義發(fā)送一些消息到后臺,甚至執(zhí)行一些銀行交易行為。

避免 XSS 攻擊在 Yii 中非常簡單,有如下兩種一般情況:

你希望數(shù)據(jù)以純文本輸出。

你希望數(shù)據(jù)以 HTML 形式輸出。

如果你需要的是純文本,你可以如下簡單的轉(zhuǎn)義:

如果是 HTML ,我們可以用 HtmlPurifier 幫助類來執(zhí)行:

注意: HtmlPurifier 幫助類的處理過程較為費時,建議增加緩存:

防止 CSRF 攻擊
CSRF 是跨站請求偽造的縮寫。這個攻擊思想源自許多應(yīng)用程序假設(shè)來自用戶的瀏覽器請求是由用戶自己產(chǎn)生的,而事實并非如此。

比如說:an.example.com 站點有一個 /logout URL,當(dāng)以 GET 請求訪問時,登出用戶。如果它是由用戶自己操作的,那么一切都沒有問題。但是,有一天壞人在一個用戶經(jīng)常訪問的論壇發(fā)了一個

 

內(nèi)容的帖子。瀏覽器無法辨別請求一個圖片還是一個頁面,所以,當(dāng)用戶打開含有上述標(biāo)簽的頁面時,他將會從 an.example.com 登出。

上面就是最原始的思想。有人可能會說,登出用戶也不是什么嚴(yán)重問題,然而,我們發(fā)送一些 POST 數(shù)據(jù)其實也不是很麻煩的事情。

為了避免 CSRF 攻擊,你總是需要:

遵循 HTTP 準(zhǔn)則,比如 GET 不應(yīng)該改變應(yīng)用的狀態(tài)。

保證 Yii CSRF 保護開啟。

防止文件暴露

默認(rèn)的服務(wù)器 webroot 目錄指向包含有 index.php 的 web 目錄。

在共享托管環(huán)境下,這樣是不可能的,這樣導(dǎo)致了所有的代碼,配置,日志都在webroot目錄。

如果是這樣,別忘了拒絕除了 web 目錄以外的目錄的訪問權(quán)限。如果沒法這樣做,考慮將你的應(yīng)用程序托管在其他地方。

在生產(chǎn)環(huán)境關(guān)閉調(diào)試信息和工具

在調(diào)試模式下, Yii 展示了大量的錯誤信息,這樣是對開發(fā)有用的。同樣,這些調(diào)試信息對于攻擊者而言也是方便其用于破解數(shù)據(jù)結(jié)構(gòu),配置值,以及你的部分代碼。

永遠不要在生產(chǎn)模式下將你的 index.php 中的 YII_DEBUG 設(shè)置為 true。

你同樣也不應(yīng)該在生產(chǎn)模式下開啟 Gii。

它可以被用于獲取數(shù)據(jù)結(jié)構(gòu)信息,代碼,以及簡單的用 Gii 生成的代碼覆蓋你的代碼。

調(diào)試工具欄同樣也應(yīng)該避免在生產(chǎn)環(huán)境出現(xiàn),除非非常有必要。它將會暴露所有的應(yīng)用和配置的詳情信息。如果你確定需要,反復(fù)確認(rèn)其訪問權(quán)限限定在你自己的 IP。

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/21642.html

相關(guān)文章

  • Yii修行之路 - Gii 代碼生成器

    摘要:簡述是一個強大的代碼生成器,主要用于后臺代碼生成。下面列出由生成的文件,以便你研習(xí)功能和實現(xiàn),或修改它們控制器模型和視圖補充被設(shè)計成高度可定制和可擴展的代碼生成工具。使用生成代碼是一個基于界面的代碼生成工具。 簡述 Gii 是一個強大的代碼生成器,主要用于后臺代碼生成。 開始 Gii Gii 是 Yii 中的一個模塊。可以通過配置應(yīng)用的 yiibaseApplication::modu...

    fuchenxuan 評論0 收藏0
  • Yii修行之路 - Console 控制臺命令

    摘要:它由一個或多個類組成,它們在控制臺環(huán)境下通常被稱為命令。控制臺入口腳本通常被稱為,位于應(yīng)用程序的根目錄。選項通過覆蓋在中的方法,你可以指定可用于控制臺命令選項。參數(shù)將傳遞給請求的子命令對應(yīng)的操作方法。通常,執(zhí)行成功的命令會返回。 簡述 控制臺應(yīng)用程序的結(jié)構(gòu)非常類似于 Yii 的一個 Web 應(yīng)用程序,主要用于終端服務(wù)器執(zhí)行。 控制臺命令 控制臺應(yīng)用程序的結(jié)構(gòu)非常類似于 Yii 的一個 ...

    everfly 評論0 收藏0
  • Yii修行之路 - Migration 數(shù)據(jù)遷移

    摘要:把所有的增量數(shù)據(jù)庫遷移提交到生產(chǎn)環(huán)境數(shù)據(jù)庫當(dāng)中。如果其中任意一個遷移提交失敗了,那么這條命令將會退出并停止剩下的那些還未執(zhí)行的遷移。執(zhí)行這條命令期間不會有任何的遷移會被提交或還原。 簡述 數(shù)據(jù)遷移就是數(shù)據(jù)庫表在團隊建的遷移操作,達到團隊相互間的信息同步,數(shù)據(jù)統(tǒng)一。 數(shù)據(jù)庫遷移 一般步驟: 1、在 yii2 的 migrate 中,通常用來對數(shù)據(jù)庫數(shù)據(jù)表進行修改操作,主要對結(jié)構(gòu)和小部分?jǐn)?shù)...

    noONE 評論0 收藏0
  • Yii修行之路 - Errors(錯誤處理) & Logging(日志記錄)

    摘要:簡述這里簡單歸納總結(jié)關(guān)于的錯誤處理和日志記錄的操作。錯誤處理器會正確地設(shè)置響應(yīng)的狀態(tài)碼并使用合適的錯誤視圖頁面來顯示錯誤信息。記錄一個警告消息用來指示一些已經(jīng)發(fā)生的意外。的義務(wù)是正確處理日志消息。相應(yīng)的消息通過被記錄。 簡述 這里簡單歸納總結(jié)關(guān)于Yii的錯誤處理和日志記錄的操作。 錯誤處理(Errors) Yii 內(nèi)置了一個yiiwebErrorHandler錯誤處理器,它使錯誤處理更...

    _ang 評論0 收藏0
  • Yii修行之路 - View 視圖渲染

    摘要:簡述模塊是中的架構(gòu)的板塊,主要負(fù)責(zé)數(shù)據(jù)的展示,渲染模板文件,展示數(shù)據(jù)內(nèi)容。此外在一個視圖中還可以引入多個視圖文件,也是通過方法實現(xiàn)。布局文件的數(shù)據(jù)默認(rèn)以顯示,也可以用數(shù)據(jù)塊的形式渲染到視圖上。必須要確認(rèn)生成一次,才會正式生成新首頁。 簡述 View模塊是Yii中的MVC架構(gòu)的V板塊,主要負(fù)責(zé)數(shù)據(jù)的展示,渲染模板文件,展示數(shù)據(jù)內(nèi)容。 基本概念 MVC在Yii里面有一個Views文件夾,里...

    Mr_houzi 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<