Yii2使用RESTful API及其认证问题

Yii 提供了一整套用来简化实现 RESTful 风格的 Web Service 服务的 API。

1.修改config/main.php文件,在components添加

1
2
3
4
5
6
7
8
9
10
11
12
13
'urlManager' => [
'enablePrettyUrl' => true,
'enableStrictParsing' => true,
'showScriptName' => false,
'rules' => [
['class' => 'yii\rest\UrlRule',
'controller' => [
'......',
'product', //对应ProductController
]
],
],
],

2.修改common/models/User.PHP

1
2
3
4
public static function findIdentityByAccessToken($token, $type = null)
{

return static::findOne(['access_token' => $token]);
}

3.在Controllers中新建ProductController.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
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 服务器。

1
2
3
4
yii\filters\auth\CompositeAuth
yii\filters\auth\HttpBasicAuth
yii\filters\auth\HttpBearerAuth
yii\filters\auth\QueryParamAuth

QueryParamAuth:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
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}\"");
}
}
八宝粥 wechat
欢迎您扫一扫上面的微信公众号,订阅我的博客!