和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數據表,正式環境請分離不一樣的數據表來進行認證)數據庫
準備條件api
繼上篇的 User
數據表,咱們還須要增長一 個access_token
的字段,數組
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');
}
複製代碼
執行遷移命令bash
php yii migrate
複製代碼
瀏覽器打開前臺目錄 frontend 頁面,點擊註冊帳號,先註冊一個帳號服務器
打開 api\config\main.php
cookie
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;
}
}
複製代碼
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
屬性,添加下列代碼:
'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
來進行攜帶
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' => '用戶名或密碼錯誤!'
];
複製代碼
水平有限,不免有紕漏,請不吝賜教,在下會感激涕零