Yii2 RESTful API Auth Mechanism
2015-06-08 09:00
676 查看
| | | |~filters/ | | | | |~auth/ | | | | | |-AuthInterface.php | | | | | |-AuthMethod.php | | | | | |-CompositeAuth.php | | | | | |-HttpBasicAuth.php | | | | | |-HttpBearerAuth.php | | | | | `-QueryParamAuth.php
一、HttpBearer
验证方式:
<?php namespace app\controllers; use yii\rest\ActiveController; use yii\filters\auth\HttpBasicAuth; use yii\helpers\ArrayHelper; #use yii\filters\auth\CompositeAuth; #use yii\filters\auth\HttpBasciAuth; use yii\filters\auth\HttpBearerAuth; #use yii\filters\auth\QueryParamAuth; class UsersController extends ActiveController { public $modelClass = 'app\models\User2'; public function behaviors() { return ArrayHelper::merge(parent::behaviors(), [ 'authenticator' => [ 'class' => HttpBearerAuth::className(), #这个地方使用`ComopositeAuth` 混合认证 #'class' => CompositeAuth::className(), #`authMethods` 中的每一个元素都应该是 一种 认证方式的类或者一个 配置数组 //'authMethods' => [ //HttpBasicAuth::className(), //HttpBearerAuth::className(), //QueryParamAuth::className(), //] ] ]); }
下面来分析相关的源码,看看 yii2/rest 是如何处理权限验证的。
<?php /** * @link http://www.yiiframework.com/ * @copyright Copyright (c) 2008 Yii Software LLC * @license http://www.yiiframework.com/license/ */ namespace yii\filters\auth; use Yii; use yii\web\UnauthorizedHttpException; /** * HttpBearerAuth is an action filter that supports the authentication method based on HTTP Bearer token. * * You may use HttpBearerAuth by attaching it as a behavior to a controller or module, like the following: * * public function behaviors() * { * return [ * 'bearerAuth' => [ * 'class' => \yii\filters\auth\HttpBearerAuth::className(), * ], * ]; * } * * @author Qiang Xue <qiang.xue@gmail.com> * @since 2.0 */ class HttpBearerAuth extends AuthMethod { /** * @var string the HTTP authentication realm */ public $realm = 'api'; /** * @inheritdoc */ public function authenticate($user, $request, $response) { $authHeader = $request->getHeaders()->get('Authorization'); if ($authHeader !== null && preg_match("/^Bearer\\s+(.*?)$/", $authHeader, $matches)) { $identity = $user->loginByAccessToken($matches[1], get_class($this)); if ($identity === null) { $this->handleFailure($response); } return $identity; } return null; } /** * @inheritdoc */ public function handleFailure($response) { $response->getHeaders()->set('WWW-Authenticate', "Bearer realm=\"{$this->realm}\""); throw new UnauthorizedHttpException('You are requesting with an invalid access token.'); } }
要想顺利通过此验证,需要在
Header中加入一项:
Authorization:Bearer ganiks-token
如果没有如上提供正确的
access-token, 则会得到一个:
401 Unauthorized Www-Authenticate:Bearer realm="api"
二、HttpBasic
验证方式:
class HttpBasicAuth extends AuthMethod { /** * @var string the HTTP authentication realm */ public $realm = 'api'; /** * @var callable a PHP callable that will authenticate the user with the HTTP basic auth information. * The callable receives a username and a password as its parameters. It should return an identity object * that matches the username and password. Null should be returned if there is no such identity. * * The following code is a typical implementation of this callable: * * function ($username, $password) { * return \app\models\User::findOne([ * 'username' => $username, * 'password' => $password, * ]); * } * * If this property is not set, the username information will be considered as an access token * while the password information will be ignored. The [[\yii\web\User::loginByAccessToken()]] * method will be called to authenticate and login the user. */ public $auth; /** * @inheritdoc */ public function authenticate($user, $request, $response) { $username = $request->getAuthUser(); $password = $request->getAuthPassword(); if ($this->auth) { if ($username !== null || $password !== null) { $identity = call_user_func($this->auth, $username, $password); if ($identity !== null) { $user->switchIdentity($identity); } else { $this->handleFailure($response); } return $identity; } } elseif ($username !== null) { $identity = $user->loginByAccessToken($username, get_class($this)); if ($identity === null) { $this->handleFailure($response); } return $identity; } return null; } /** * @inheritdoc */ public function handleFailure($response) { $response->getHeaders()->set('WWW-Authenticate', "Basic realm=\"{$this->realm}\""); throw new UnauthorizedHttpException('You are requesting with an invalid access token.'); } }
如果要顺利通过此验证,有2种方式:
access-token作为
Basci Auth的
username一起请求,至于
password则不必管
定义下
use yii\filters\auth\HttpBasciAuth的
$auth为一个验证的方法,来根据请求中的
username:password来返回一个
identity
默认的,
$auth是没有定义的,此时,在Header中加入:
Authorization:Basic Z2FuaWtzLXRva2VuOg==
这个码是由
username: ganiks-token经过base64编码得到的,可以得到正确的响应
反而是用
username:password(正确的)也无法得到响应
第二种方式,
可以配置
use yii\filters\auth\HttpBasciAuth的
$auth为一个
callable如下:
public $auth; public function auth ($username, $password) { return \app\models\User2::findOne([ 'username' => $username, 'password' => $password, ]); }
这里是个遗留问题,http://www.yiiframework.com/forum/index.php/topic/56916-how-to-define-a-callable-variable-for-a-class/
下面是一个临时的解决方案,使用 username:password_hash
验证
<?php /** * @link http://www.yiiframework.com/ * @copyright Copyright (c) 2008 Yii Software LLC * @license http://www.yiiframework.com/license/ */ namespace yii\filters\auth; use Yii; use yii\web\UnauthorizedHttpException; class HttpBasicAuth extends AuthMethod { public $auth; public function auth ($username, $password) { return \app\models\User2::findOne([ 'username' => $username, 'password_hash' => $password, ]); } /** * @inheritdoc */ public function authenticate($user, $request, $response) { $username = $request->getAuthUser(); $password = $request->getAuthPassword(); if ($this->auth($username, $password)) { if ($username !== null || $password !== null) { //$identity = call_user_func($this->auth, $username, $password); $identity = $this->auth($username, $password); if ($identity !== null) { $user->switchIdentity($identity); } else { $this->handleFailure($response); } return $identity; } } elseif ($username !== null) { $identity = $user->loginByAccessToken($username, get_class($this)); if ($identity === null) { $this->handleFailure($response); } return $identity; } return null; } /** * @inheritdoc */ public function handleFailure($response) { $response->getHeaders()->set('WWW-Authenticate', "Basic realm=\"{$this->realm}\""); throw new UnauthorizedHttpException('You are requesting with an invalid access token.'); } }
三、QueryParam
验证方式:
此方式最简单,只需要在请求的URL后面加上?access-toekn=ganiks-token即可验证
class QueryParamAuth extends AuthMethod { /** * @var string the parameter name for passing the access token */ public $tokenParam = 'access-token'; /** * @inheritdoc */ public function authenticate($user, $request, $response) { $accessToken = $request->get($this->tokenParam); if (is_string($accessToken)) { $identity = $user->loginByAccessToken($accessToken, get_class($this)); if ($identity !== null) { return $identity; } } if ($accessToken !== null) { $this->handleFailure($response); } return null; } /** * @inheritdoc */ public function handleFailure($response) { throw new UnauthorizedHttpException(Yii::t('yii', 'You are requesting with an invalid access token.')); }
四、compositeAuth
综合验证方式:
class CompositeAuth extends AuthMethod { /** * @var array the supported authentication methods. This property should take a list of supported * authentication methods, each represented by an authentication class or configuration. * * If this property is empty, no authentication will be performed. * * Note that an auth method class must implement the [[\yii\filters\auth\AuthInterface]] interface. */ public $authMethods = []; /** * @inheritdoc */ public function beforeAction($action) { return empty($this->authMethods) ? true : parent::beforeAction($action); } /** * @inheritdoc */ public function authenticate($user, $request, $response) { foreach ($this->authMethods as $i => $auth) { $this->authMethods[$i] = $auth = Yii::createObject($auth); if (!$auth instanceof AuthInterface) { throw new InvalidConfigException(get_class($auth) . ' must implement yii\filters\auth\AuthInterface'); } $identity = $auth->authenticate($user, $request, $response); if ($identity !== null) { return $identity; } } if (!empty($this->authMethods)) { /* @var $auth AuthInterface */ $auth = reset($this->authMethods); $auth->handleFailure($response); } return null; }
相关文章推荐
- Yii2 RESTful API开发的相关模型
- Yii2 Restful API 原理分析
- Yii2的RESTful API开发
- Yii2 API认证和授权
- Yii2 XSS 防范策略
- Yii2详解Model类
- php正则表达式—对于文字匹配的建议
- 从Yii2的Request看其CSRF防范策略
- Yii2为ActiveForm的widget组件设置属性
- Yii2中的OAuth扩展及QQ互联登录
- Yii2 Unable to verify your data submission.
- Yii2 使用Ajax自动获取表单数据
- Yii2 DropDownList用法
- Yii 2发送带附件的邮件
- Yii2上传文件
- Yii2 实现上下联动的下拉框
- Yii2同时搜索多个字段
- Yii2让关联字段支持搜索功能
- Yii2中多表关联查询(hasOne、hasMany、join、joinwith)
- Yii2关联查询用法