oauth1.a&2.0以get,head,post请求access_token[php]

 忽如一夜春风来,千万开放平台开。然而开放平台不是开房平台,你需要先申请一个叫access_token的东东。这个东西就是你在开放平台上的应用(consumer)、开放平台、使用你的应用来访问自身数据客户的一个三方契约;契约写明本用户允许consumer访问本用户在开房平台上的数据;consumer每次拿着这个契约给开房平台看一下,就可以大摇大摆的取得想要的数据了。

取得access token常用的有两种方法:oauth1.a和oauth2.0(本来存在oauth1.0,后来因为安全性问题被弃用)。流程开始之前,你必须为你的应用申请一个consumer_key(任意申请key和token都会附带secret,secret在2.0里面基本没啥用),consumer_key用于申请,consumer_secret+当前其他token附带的secret用于提取传输参数的签名,校验正确性。

oauth1.a是一种比较繁琐的认证流程。它要先使用consumer_key申请一个未授权的request token,用户授权之后变为授权的request token并生成一个verified以get方式送到应用的回调地址(无回调地址即ood,会发送一个pin code到浏览器),然后应用将发送授权的request_token(事实上和未授权的一样,因此上步不存在新的secret)+verified申请access_token. 之后调用api时需要将access token+函数参数+(consumer_secret+access_secret)提取签名发送到开房平台,开放平台将函数结果返回。

oauth2一种存在4中方式申请,采用了https加密,因此不用个人手动提取签名,且认证步骤简化,所以说简单很多。另外,其返回结果通常是以json格式返回。在此就不一一解释了。

Http请求数据可以有多种方式,在开放平台中接受三种: post, get, head. post将数据放在http请求体中,get将请求数据放在网址中和网址以?分割,head不是head request是把请求放在head中,实验表明其方式是get. 具体实验写在后面。由于get是将所有数据以近乎于明文的方式拼接到网址,因此post,head相对安全点,所以在发送某些敏感数据时推荐使用post。

============================================烦人的理论到此为止=============================================================

在oauth1.a&2.0申请token过程中,需要发送多次http请求,有些需要请求需要浏览器重定向。所以先封装各种不同的用于发送的http请求的类,使用了一个工厂,方便调用不同的请求方式。

 

sender.php
<?php
abstract class Sender{
    public abstract function send($url, $data);
}

abstract class GetSender extends Sender{
    protected function makeUrl($aUrl, $data){
        $url=$aUrl.'?';
        foreach($data as $key=>$value){
            if($url.chr(strlen($url)-1)!='?'){
                $url.='&';
            }
            $url=$url.$key.'='.$value;
        }
        return $url;
    }
}

abstract class PostSender extends Sender{
}

abstract class HeadSender extends Sender{
    protected function makeHead($data){
        $head = array();
        if(array_key_exists('oauth_version', $data) && $data['oauth_version']=='1.0'){
            $head[0] = 'Authorization: OAuth ';
        }else{
            $head[0] = 'Authorization: OAuth2 ';
        }
        foreach($data as $key=>$value){
            $head[0] = $head[0].$key.'='.$value.',';
        }
        $head[0][strlen($head[0])-1]=null;
        return $head;
    }
}

class RedirectGetSender extends GetSender{
    public function send($url, $data){
        $url = $this->makeUrl($url, $data);
        header("Location:$url");
    }
}

class DirectGetSender extends GetSender{
    public function send($url, $data){
        $url = $this->makeUrl($url, $data);
        $result = file_get_contents($url);
        return $result;
    }
}
class RedirectPostSender extends PostSender{
    public function send($url, $data){
        echo "click submit to authorize!<br>";
        echo '<form action="'.$url.'" method="post">';
        foreach($data as $key=>$value){
            echo '<input type="hidden" name='.$key.' value="'.$value.'"/>';
        }
        echo '<input type="submit" value="SBUMIT">';
        echo '</form>';
    }
}
class DirectPostSender extends PostSender{
    public function send($url, $data){
        $curlHandle = curl_init();
        curl_setopt($curlHandle, CURLOPT_URL, $url);
        curl_setopt($curlHandle, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($curlHandle, CURLOPT_HTTPHEADER, array('Expect:'));
        curl_setopt($curlHandle, CURLOPT_POST, true);
        curl_setopt($curlHandle, CURLOPT_POSTFIELDS, http_build_query($data));
        $result = curl_exec($curlHandle);
        curl_close($curlHandle);
        return $result;
    }
}
class DirectHeadSender extends HeadSender{
    public function send($url, $data){
        $head = $this->makeHead($data);
        $curlHandle = curl_init();
        curl_setopt($curlHandle, CURLOPT_URL, $url);
        curl_setopt($curlHandle, CURLOPT_HEADER, false);
        curl_setopt($curlHandle, CURLOPT_HTTPHEADER, $head);
        curl_setopt($curlHandle, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($curlHandle, CURLOPT_FRESH_CONNECT, 1);
        $result = curl_exec($curlHandle);
        curl_close($curlHandle);
        return $result;
    }
}
class RedirectHeadsender extends HeadSender{
    public function send($url, $data){
        echo "There are no head method for this redirect request!<br>";
    }
}
class SenderFactory{
    public static function createSender($isRedirect, $mode){
        switch (strtolower($mode)){
        case "get":
            if($isRedirect===true){
                return new RedirectGetSender();
            }else{
                return new DirectGetSender();
            }
            break;
        case "post":
            if($isRedirect===true){
                return new RedirectPostSender();
            }else{
                return new DirectPostSender();
            }
            break;
        case "head":
            if($isRedirect ===true){
                return new RedirectHeadSender();
            }else{
                return new DirectHeadSender();
            }
            break;
        }
    }
}
?>


--------------------------------------oauth1.a----------------------------------------------------------

url->base string类;签名类:

url.php
<?php
class Helper_URL
{
    /**
     * * Build HTTP Query
     * *
     * * @param array $params Name => value array of 
     * parameters
     * *
     * * @return string HTTP query
     * */
    public static function buildHttpQuery(array $params)
    {
        if (empty($params)) {
            return '';
        }

        $keys   = self::urlEncode(array_keys($params));
        $values = self::urlEncode(array_values($params));
        $params = array_combine($keys, $values);
        uksort($params, 'strcmp');
        $pairs = array();
        foreach ($params as $key => $value) {
            $pairs[] =  $key . '=' . $value;
        }
        return implode('&', $pairs);
    }
    /**
     * * URL Encode
     * *
     * * @param mixed $item string or array of items 
     * to url encode;
     * *
     * * @return mixed url encoded string 
     * or array of strings
     * */
    public static function urlEncode($item)
    {
        static $search  = array('%7E');
        static $replace = array('~');
        if (is_array($item)) {
            return array_map(array(__CLASS__, 'urlEncode'), $item);
        }
        if (is_scalar($item) === false) {
            return $item;
        }
        return str_replace($search, $replace, rawurlencode($item));
    }
    /**
     * * URL Decode
     * *
     * * @param mixed $item Item to url decode
     * *
     * * @return string URL decoded string
     * */
    public static function urlDecode($item)
    {
        if (is_array($item)) {
            return array_map(array(__CLASS__, 'urlDecode'), $item);
        }
        return rawurldecode($item);
    }
}
?>


 

signature.php
<?php
include_once('url.php');
/*
 * This class is used to generate the signature of base string.
 * $url is the url your request will be sended to. and if in 'get' mode it is 
 * only the part before '?';
 * $reqMod is request mode: 'get', 'post'; when paremeters are put in the head, 
 * its request mode is 'get';
 * $params are all the params except 'oauth_signature';
 * $consumerSecret is your consumer_secret;
 * $token_secret is the secret you got in the nearest formal step;
 */
class Signaturer{
    public function getSignature($url, $reqMode, array $params, $consumerSecret, $tokenSecret=''){
        $baseStr = $this->getBaseStr($reqMode, $url, $params);
        if(isSet($params['oauth_signature_method'])){
            $signMethod = $this->getSignMethod($params['oauth_signature_method']);
        }else{
            $signMethod = 'sha1';
        }
        $key = $this->getKey($consumerSecret, $tokenSecret);
        return base64_encode(hash_hmac($signMethod, $baseStr, $key, true));
    }

    /* used for constructing the base string.
     * */
    public function getBaseStr($method, $url, $params){
        if (array_key_exists('oauth_signature', $params)) {
            unset($params['oauth_signature']);
        }
        $urlParts = explode('?', $url);
        $parts = array(strtoupper($method), $urlParts[0], Helper_URL::buildHTTPQuery($params));
        return implode('&', Helper_URL::urlEncode($parts));
    }

    /*
     * used to analyse signature method automatically
     * */
    public function getSignMethod($signMethod){
        list($begin, $end) = explode('-', $signMethod);
        return strtolower($end);
    }
    /*
     * create key for signature;
     * in the first step, since there is no secret, it is "$consumerSecret&"
     * */
    public function getKey($consumerSecret, $tokenSecret = ''){
        $secrets = array($consumerSecret, $tokenSecret);
        return implode('&', Helper_URL::urlEncode($secrets));
    }
}

?>


 

oauthTokenFetcher.php
<?php
include_once('sender.php');
include_once('signaturer.php');
/* 
 * to apply an access_token, there are three step:
 * 1. consumer (get post head) a request for unauthorised_request_token and an 
 * unauthorizised request token would be sended back;
 * 2. consumer redirect to the authorization center url;
 * 3. consumer get the authorized request token in the callback url; and then 
 * consumer (get post head) a request for access token; finally, an access 
 * token is sended back;
 */

class OauthTokenFetcher{
    private $signaturer;
	function __construct(){
		$this->signaturer = new Signaturer();
	}
	public function setNonceStamp(array &$params){
		$params['oauth_nonce'] = md5(mt_rand());
		$params['oauth_timestamp'] = time();
	}
    public function fetchToken($url, $reqMode, array $params, $consumerSecret, $tokenSecret, $tokenStyle='request_token'){
        $reqParam = strtolower($reqMode)==='head'?'get':$reqMode;
		$params['oauth_signature'] = $this->signaturer->getSignature($url, $reqParam, $params, $consumerSecret, $tokenSecret);
        foreach($params as $key=>$value){
            $params[$key] = Helper_URL::urlEncode($value);
        }
        if($tokenStyle === 'request_token'){
            $sender = SenderFactory::createSender(true, $reqMode);
            $sender->send($url, $params);
        }else{
            $sender = SenderFactory::createSender(false, $reqMode);
            $result = $sender->send($url, $params);
            return $result;
        }
    }
    /*
     * parse return of fetchToken
     * */
    public function parse($str){
		$infoTmps = explode('&', $str);
		$info = array();
		foreach($infoTmps as $value){
			list($begin, $end) = explode('=', $value);
			$info[$begin] = $end;
		}
		return $info;
	}
}
?>

 

--待续--

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值