和Web應用不一樣,RESTful
APIs
一般是無狀態的, 也就意味着不該使用 sessions
或 cookies
, 所以每一個請求應附帶某種受權憑證,由於用戶受權狀態可能沒經過 sessions
或 cookies
維護, 經常使用的作法是每一個請求都發送一個祕密的 access token
來認證用戶, 因爲 access token
能夠惟一識別和認證用戶,API
請求應經過 HTTPS
來防止man-in-the-middle (MitM) 中間人攻擊.php
access token
看成API URL請求參數發送,例如 https://example.com/users?access-token=xxxxxxxx
, 因爲大多數服務器都會保存請求參數到日誌, 這種方式應主要用於JSONP
請求,由於它不能使用HTTP頭來發送 access token
OAuth2
協議的 access token
, 而後經過 HTTP Bearer Tokens
發送到 API
服務器。上方進行簡單介紹,內容來自 Yii Framework 2.0 權威指南web
咱們都知道 Yii2.0
默認的認證類都是 User
,先後臺都是共用一個認證類,所以咱們要把API
認證類 單獨分離出來,達到前、後、API都分離,
繼上一章:(這裏暫時使用默認User數據表,正式環境請分離不一樣的數據表來進行認證)數據庫
準備條件
繼上篇的 User
數據表,咱們還須要增長一 個access_token
的字段,api
access_token
字段。進入項目根目錄打開控制檯輸入如下命令:數組
php yii migrate/create add_access_token_to_user
打開 你的項目目錄/console/migrations/m180704_054630_add_access_token_to_user.php
修改以下內容:瀏覽器
public function safeUp() { $this->addColumn('user', 'access_token', $this->string()); } public function safeDown() { $this->dropColumn('user', 'access_token'); }
執行遷移命令安全
php yii migrate
瀏覽器打開前臺目錄 frontend 頁面,點擊註冊帳號,先註冊一個帳號
打開 api\config\main.php
服務器
user
應用組件:* 設置 `identityClass` 屬性爲哪一個認證類 * 設置 `enableSession` 屬性爲 `false` * 設置 `enableAutoLogin` 屬性爲 `true`
session
組件註釋掉,或刪掉'user' => [ 'identityClass' => 'api\models\User', 'enableAutoLogin' => true, 'enableSession'=>false, //'identityCookie' => ['name' => '_identity-backend', 'httpOnly' => true], ], //'session' => [ // this is the name of the session cookie used for login on the backend // 'name' => 'advanced-backend', // ],
api\models\User.php
實現認證類,繼承 IdentityInterface
將 common\models\User
類拷貝到 api\models\
目錄下,修改命名空間爲api\models
cookie
<?php namespace api\models; use Yii; use yii\base\NotSupportedException; use yii\behaviors\TimestampBehavior; use yii\db\ActiveRecord; use yii\web\IdentityInterface; ... class User extends ActiveRecord implements IdentityInterface { ... ... }
common\models\LoginForm.php
類拷貝到api\models\
目錄下,修改命名空間,並重寫login方法:<?php namespace api\models; use Yii; use yii\base\Model; ... ... public function login() { if ($this->validate()) { $access_token=$this->_user->generateAccessToken(); $this->_user->save(); return $access_token; } else { return false; } }
generateAccessToken()
方法,所以咱們到api\models\User.php
中添加此方法namespace api\models; use Yii; use yii\base\NotSupportedException; use yii\behaviors\TimestampBehavior; use yii\db\ActiveRecord; use yii\web\IdentityInterface; ... ... class User extends ActiveRecord implements IdentityInterface { ... ... /** * 生成accessToken字符串 * @return string * @throws \yii\base\Exception */ public function generateAccessToken() { $this->access_token=Yii::$app->security->generateRandomString(); return $this->access_token; } }
User
控制器編寫登陸方法use api\models\LoginForm; ... ... //省略一些代碼 /** * 登錄 * @return array * @throws \yii\base\Exception * @throws \yii\base\InvalidConfigException */ public function actionLogin() { $model = new LoginForm(); if ($model->load(Yii::$app->getRequest()->getBodyParams(), '') && $model->login()) { return [ 'access_token' => $model->login(), ]; } else { return $model->getFirstErrors(); } } ...
打開 api\config\main.php
修改 components
屬性,添加下列代碼:session
'urlManager' => [ 'enablePrettyUrl' => true, 'enableStrictParsing' => true, 'showScriptName' => false, 'rules' => [ ['class' => 'yii\rest\UrlRule', 'controller' => 'user', 'extraPatterns'=>[ 'POST login'=>'login', ], ], ], ]
http://youdomain/users/login
記住是POST
請求發送,假如用POSTMAN
有問題的話指定一下 Content-Type:application/x-www-form-urlencoded
。ok,不出意外的話,相信你已經能夠收到一個access_token了,接下來就是如何使用這個token,如何維持認證狀態,達到不攜帶這個token將沒法訪問,返回401
實現認證只需兩步:
REST
控制器類中配置 authenticator
行爲來指定使用哪一種認證方式接下來咱們圍繞這兩步來實現:
User
數據表吧api\controllers\
新加一個控制器 命名爲 ArticleController
並繼承 yii\rest\ActiveController
,配置認證方式代碼:代碼以下:<?php namespace api\controllers; use yii\rest\ActiveController; use Yii; use yii\filters\auth\CompositeAuth; use yii\filters\auth\HttpBasicAuth; use yii\filters\auth\HttpBearerAuth; use yii\filters\auth\QueryParamAuth; class ArticleController extends ActiveController { public $modelClass = 'api\models\User'; public function behaviors() { $behaviors = parent::behaviors(); $behaviors['authenticator'] = [ 'class' => CompositeAuth::className(), 'authMethods' => [ HttpBasicAuth::className(), HttpBearerAuth::className(), QueryParamAuth::className(), ], ]; return $behaviors; } }
注意:這個控制器並不是真正的Article,實則仍是User
findIdentityByAccessToken()
方法:打開 api\models\User.php
重寫 findIdentityByAccessToken()
方法
... ... class User extends ActiveRecord implements IdentityInterface { ... ... public static function findIdentityByAccessToken($token, $type = null) { return static::findOne(['access_token' => $token]); } ... }
修改 api\config\main.php
'urlManager' => [ 'enablePrettyUrl' => true, 'enableStrictParsing' => true, 'showScriptName' => false, 'rules' => [ ['class' => 'yii\rest\UrlRule', 'controller' => 'user', 'extraPatterns'=>[ 'GET send-email'=>'send-email' 'POST login'=>'login', ], ], ['class' => 'yii\rest\UrlRule', 'controller' => 'article', 'extraPatterns'=>[ ], ], ], ]
接下來訪問一下你的域名 http://youdomain/articles
,不攜帶任何參數是否是返回 401了?
ok,這裏介紹兩種訪問方式,一種是URL訪問,另外一種是經過header
來進行攜帶
header
頭信息Authorization:Bearer y3XWtwWaxqCEBDoE-qzZk0bCp3UKO920
注意 Bearer 和你的token中間是有 一個空格的,不少同窗在這個上面碰了不少次
好啦,基於YII2.0 RESTful 認證就此結束了,
更過完整的功能 請移步官方文檔
受權驗證
另外還有速率驗證,就自行發覺吧
另外,若是看不懂,或者寫的很差,請移步 魏曦 老師的視頻教程,本人全部內容都是跟隨 魏曦老師 學的
魏曦教你學
寫完認證發現咱們的接口返回的數據不是很直觀,現實生活中一般也不是這樣子的,咱們可能會返回一些特定的格式
打開 api\config\main.php
在 components
數組裏面添加以下內容分
'response' => [ 'class' => 'yii\web\Response', 'on beforeSend' => function ($event) { $response = $event->sender; $response->data = [ 'success' => $response->isSuccessful, 'code' => $response->getStatusCode(), 'message' => $response->statusText, 'data' => $response->data, ]; $response->statusCode = 200; }, ],
這裏的狀態碼統一設爲 200 ,具體的可另行配置,假如登錄操做 密碼錯誤或者其餘,咱們能夠在控制器中這樣使用:
$response = Yii::$app->response; $response->setStatusCode(422); return [ 'errmsg' => '用戶名或密碼錯誤!' ];
水平有限,不免有紕漏,請不吝賜教,在下會感激涕零