和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' => '用户名或密码错误!' ];
水平有限,不免有纰漏,请不吝赐教,在下会感激涕零