八宝粥 2016-06-24 09:18:38 15409次浏览 3条评论 2 4 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}\"");
    }
}
觉得很赞
您需要登录后才可以评论。登录 | 立即注册