Yii2使用RESTful API及其认证问题 [ 2.0 版本 ]
Yii 提供了一整套用来简化实现 RESTful 风格的 Web Service 服务的 API。
1.修改config/main.php文件,在components添加
'urlManager' => [
'enablePrettyUrl' => true,
'enableStrictParsing' => true,
'showScriptName' => false,
'rules' => [
['class' => 'yii\rest\UrlRule',
'controller' => [
'......',
'product', //对应ProductController
]
],
],
],
2.修改common/models/User.PHP
public static function findIdentityByAccessToken($token, $type = null)
{
return static::findOne(['access_token' => $token]);
}
3.在Controllers中新建ProductController.php
namespace api\controllers;
use common\models\Product;
use yii\rest\ActiveController;
use yii\web\Response;
use yii\filters\auth\CompositeAuth;
use yii\filters\auth\HttpBasicAuth;
use yii\filters\auth\HttpBearerAuth;
use yii\filters\auth\QueryParamAuth;
class CategoryController extends ActiveController
{
public $modelClass = 'common\models\Product';
public function behaviors()
{
$behaviors = parent::behaviors();
$behaviors['contentNegotiator']['formats']['text/html'] = Response::FORMAT_JSON;
$behaviors['authenticator'] = [
//auth method 1
//'class' => HttpBasicAuth::className(),
//auth method 2
'class' => HttpBearerAuth::className(),
//auth method 3
//'class' => QueryParamAuth::className(),
//auth method 4
'class' => CompositeAuth::className(),
'authMethods' => [
HttpBasicAuth::className(),
HttpBearerAuth::className(),
QueryParamAuth::className(),
],
];
return $behaviors;
}
//直接在响应主体内包含分页信息
public $serializer = [
'class' => 'yii\rest\Serializer',
'collectionEnvelope' => 'items',
];
}
4.可以通过不同的方式进行认证
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\filters\auth\CompositeAuth
yii\filters\auth\HttpBasicAuth
yii\filters\auth\HttpBearerAuth
yii\filters\auth\QueryParamAuth
QueryParamAuth:
class QueryParamAuth extends AuthMethod
{
public $tokenParam = 'access-token';
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;
}
}
HttpBearerAuth:
class HttpBearerAuth extends AuthMethod
{
public $realm = 'api';
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;
}
public function challenge($response)
{
$response->getHeaders()->set('WWW-Authenticate', "Bearer realm=\"{$this->realm}\"");
}
}
HttpBasicAuth:
class HttpBasicAuth extends AuthMethod
{
public $realm = 'api';
public $auth;
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;
}
public function challenge($response)
{
$response->getHeaders()->set('WWW-Authenticate', "Basic realm=\"{$this->realm}\"");
}
}
5.自定义接口参数
新建APIAuth继承HttpBearerAuth
namespace api\filters;
use yii\filters\auth\HttpBearerAuth;
class APIAuth extends HttpBearerAuth
{
public $realm = 'api';
public function authenticate($user, $request, $response)
{
$uid = $request->getHeaders()->get('uid');
$phone = $request->getHeaders()->get('phone');
$key = $request->getHeaders()->get('key');
if($key != sha1($uid.$phone)){
return null;
}
$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;
}
public function challenge($response)
{
$response->getHeaders()->set('WWW-Authenticate', "Bearer realm=\"{$this->realm}\"");
}
}
八宝粥 北京
注册时间:2015-04-18
最后登录:2019-01-27
在线时长:26小时12分
最后登录:2019-01-27
在线时长:26小时12分
- 粉丝30
- 金钱4425
- 威望20
- 积分4885
共 3 条评论
你好,自定义接口参数进行验证时,这些参数都要写在数据库里吗?还有客户端请求怎么写。我现在把QueryParamAuth认证方式搞通了,想写一个自定义的验证接口
不一定。。看自己怎么制定了
能配上接口使用端的调用例子就完美了。
接口可以参考这个https://github.com/ybbz/yii2-wechat-demo;
前端ajax调用
您好,在没使用,看起来好复杂啊