隔了怎麼長時間,終於到了 Yii2.0
RESTful
API
認證介紹了.
廢話不多說,直接正文開始
和Web應用不同,RESTful
APIs
通常是無狀態的, 也就意味著不應使用 sessions
或 cookies
, 因此每個請求應附帶某種授權憑證,因為使用者授權狀態可能沒通過 sessions
或 cookies
維護, 常用的做法是每個請求都傳送一個祕密的 access token
來認證使用者, 由於 access token
可以唯一識別和認證使用者,API
請求應通過 HTTPS
來防止man-in-the-middle (MitM) 中間人攻擊.
- HTTP 基本認證 :access token 當作使用者名稱傳送,應用在access token可安全存在API使用端的場景, 例如,API使用端是執行在一臺伺服器上的程式。
- 請求引數:
access token
當作API URL請求引數傳送,例如https://example.com/users?access-token=xxxxxxxx
, 由於大多數伺服器都會儲存請求引數到日誌, 這種方式應主要用於JSONP
請求,因為它不能使用HTTP頭來傳送access token
- OAuth 2 : 使用者從認證伺服器上獲取基於
OAuth2
協議的access token
, 然後通過HTTP Bearer Tokens
傳送到API
伺服器。
上方進行簡單介紹,內容來自 Yii Framework 2.0 權威指南
我們都知道 Yii2.0
預設的認證類都是 User
,前後臺都是共用一個認證類,因此我們要把API
認證類 單獨分離出來,達到前、後、API都分離,
繼上一章:(這裡暫時使用預設User資料表,正式環境請分離不同的資料表來進行認證)
準備條件
繼上篇的 User
資料表,我們還需要增加一 個access_token
的欄位,
1.直接在你的資料庫中新增 access_token
欄位。
2.使用資料遷移的方式
進入專案根目錄開啟控制檯輸入以下命令:
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
配置
開啟 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
<?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;
}
}
上方程式碼給User模型新增了一個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();
}
}
...
最後新增一條URL規則
開啟 api\config\main.php
修改 components
屬性,新增下列程式碼:
'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 identity class 類中實現 [yii\web\IdentityInterface::findIdentityByAccessToken()](https://www.yiichina.com/doc/api/2.0/yii-w...) 方法.
接下來我們圍繞這兩步來實現:
新增一個REST控制器
因我這裡暫未設計其他資料表 所以我們暫且還使用
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]);
}
...
}
為剛才新加的控制器新增路由規則(ps:好像多了一步......)
修改 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了?
上面的格式本章並不存在,你只要返回 401 即可
ok,這裡介紹兩種訪問方式,一種是URL訪問,另一種是通過header
來進行攜帶
- http://youdomain/articles?access-token=y3X...
- 傳遞
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' => '使用者名稱或密碼錯誤!'
];
水平有限,難免有紕漏,請不吝賜教,在下會感激不盡