Yii2实现QQ互联登录

Yii2中OAuth扩展及QQ互联登录的方法,实例分析了OAuth扩展的相关配置与QQ互联登陆的实现技巧。

具体如下:

php composer.phar require --prefer-dist yiisoft/yii2-authclient "*"

Quick start 快速开始

更改Yii2的配置文件config/main.php,在components中增加如下内容

'components' => [

 'authClientCollection' => [

 'class' => 'yii\authclient\Collection',

 'clients' => [

  'google' => [

  'class' => 'yii\authclient\clients\GoogleOpenId'

  ],

  'facebook' => [

  'class' => 'yii\authclient\clients\Facebook',

  'clientId' => 'facebook_client_id',

  'clientSecret' => 'facebook_client_secret',

  ],

 ],

 ]

 ...

]

更改入口文件,一般是app/controllers/SiteController.php,在function actions增加代码,同时增加回调函数successCallback,大致如下

class SiteController extends Controller

{

 public function actions()

 {

 return [

  'auth' => [

  'class' => 'yii\authclient\AuthAction',

  'successCallback' => [$this, 'successCallback'],

  ],

 ]

 }

 public function successCallback($client)

 {

 $attributes = $client->getUserAttributes();

 // user login or signup comes here

 }

}

在登录的Views中,增加如下代码

<?= yii\authclient\widgets\AuthChoice::widget([

 'baseAuthUrl' => ['site/auth']

])?>

以上是官方的说明文档,下面我们来接入QQ互联

增加QQ登录的组件 我这里是放在 common/components/QqOAuth.php 中,源代码如下

<?php

namespace common\components;

use yii\authclient\OAuth2;

use yii\base\Exception;

use yii\helpers\Json;

/**

 *

 * ~~~

 * 'components' => [

 * 'authClientCollection' => [

 *  'class' => 'yii\authclient\Collection',

 *  'clients' => [

 *  'qq' => [

 *   'class' => 'common\components\QqOAuth',

 *   'clientId' => 'qq_client_id',

 *   'clientSecret' => 'qq_client_secret',

 *  ],

 *  ],

 * ]

 * ...

 * ]

 * ~~~

 *

 * @see <a rel="nofollow" href="http://connect.qq.com/" target="_blank">http://connect.qq.com/</a>

 *

 * @author easypao <[email protected]>

 * @since 2.0

 */

class QqOAuth extends OAuth2

{

 public $authUrl = 'https://graph.qq.com/oauth2.0/authorize';

 public $tokenUrl = 'https://graph.qq.com/oauth2.0/token';

 public $apiBaseUrl = 'https://graph.qq.com';

 public function init()

 {

 parent::init();

 if ($this->scope === null) {

  $this->scope = implode(',', [

  'get_user_info',

  ]);

 }

 }

 protected function initUserAttributes()

 {

 $openid = $this->api('oauth2.0/me', 'GET');

 $qquser = $this->api("user/get_user_info", 'GET', ['oauth_consumer_key'=>$openid['client_id'], 'openid'=>$openid['openid']]);

 $qquser['openid']=$openid['openid'];

 return $qquser;

 }

 protected function defaultName()

 {

 return 'qq';

 }

 protected function defaultTitle()

 {

 return 'Qq';

 }

 /**

 * 该扩展初始的处理方法似乎QQ互联不能用,应此改写了方法

 * @see \yii\authclient\BaseOAuth::processResponse()

 */

 protected function processResponse($rawResponse, $contentType = self::CONTENT_TYPE_AUTO)

 {

   if (empty($rawResponse)) {

     return [];

   }

   switch ($contentType) {

     case self::CONTENT_TYPE_AUTO: {

       $contentType = $this->determineContentTypeByRaw($rawResponse);

       if ($contentType == self::CONTENT_TYPE_AUTO) {

   //以下代码是特别针对QQ互联登录的,也是与原方法不一样的地方

         if(strpos($rawResponse, "callback") !== false){

           $lpos = strpos($rawResponse, "(");

           $rpos = strrpos($rawResponse, ")");

           $rawResponse = substr($rawResponse, $lpos + 1, $rpos - $lpos -1);

           $response = $this->processResponse($rawResponse, self::CONTENT_TYPE_JSON);

           break;

         }

   //代码添加结束

         throw new Exception('Unable to determine response content type automatically.');

       }

       $response = $this->processResponse($rawResponse, $contentType);

       break;

     }

     case self::CONTENT_TYPE_JSON: {

       $response = Json::decode($rawResponse, true);

       if (isset($response['error'])) {

         throw new Exception('Response error: ' . $response['error']);

       }

       break;

     }

     case self::CONTENT_TYPE_URLENCODED: {

       $response = [];

       parse_str($rawResponse, $response);

       break;

     }

     case self::CONTENT_TYPE_XML: {

       $response = $this->convertXmlToArray($rawResponse);

       break;

     }

     default: {

       throw new Exception('Unknown response type "' . $contentType . '".');

     }

   }

   return $response;

 }

}

更改 config/main.php 文件,在components中增加,大致如下

'components' => [

 'authClientCollection' => [

   'class' => 'yii\authclient\Collection',

   'clients' => [

     'qq' => [

      'class'=>'common\components\QqOAuth',

      'clientId'=>'your_qq_clientid',

      'clientSecret'=>'your_qq_secret'

    ],

   ],

 ]

]

SiteController.php 就按官方那样子

public function successCallback($client)

{

 $attributes = $client->getUserAttributes();

 // 用户的信息在$attributes中,以下是您根据您的实际情况增加的代码

 // 如果您同时有QQ互联登录,新浪微博等,可以通过 $client->id 来区别。

}

最后在登录的视图文件中 增加QQ登录链接

<a href="/site/auth?authclient=qq">使用QQ快速登录</a>

php接入QQ登录OAuth2.0 过程中遇到的坑分享

前言

绝大多数网站都集成了第三方登录,降低了注册门槛,增强了用户体验。最近看了看 QQ 互联上 QQ 登录的接口文档。接入 QQ 登录的一般流程呢,是这样的:先申请开发者 -> 然后创建应用(拿到一组 AppId 和 AppKey)-> 获取 access_token -> 获取 openid -> 调用 openApi 访问或修改用户信息。

然而,从申请个人开发者开始,坑就来了。

1. 申请(个人)开发者

QQ 互联中申请开发者信息的页面,一些重点太过简陋,缺失细节,比如身份证正面照的相关拍摄细节完全没有描述,我当时就直接上传了这个“身份证正面照”,然后等了 3 天, 3 天后收到腾讯开放平台的邮件通知说审核没通过,需要手持身份证。好吧,那就重拍~~。问了客服之后确定了这个“手持身份证”拍摄的正确姿势,然后我换了平台,在腾讯开放平台中改了我的申请信息,重新上传了身份证,我注意到上传框的下面有拍摄提示,看了下是个小姐姐的手持身份证照片,挺好看的,提示友好,比 QQ 互联上的申请页面好多了。又过了 2 天之后审核通过。

所以,申请开发者的话,最好还是在腾讯开放平台申请吧,信息相对详细,也更友好,QQ 互联给人感觉好久没维护了。

2. 接口调用——发布微博

(1)发布微博的接口 add_t:必需参数为 content 微博内容。调用时必须以数组键值对方式把参数传递进去,否则会报错说没提供参数。

$qc = new QC('你的access_token', '你的openid');

$weibo = [

 'content' => '微博内容'

];

$result = $qc->add_t($weibo);

(2)发布带图片微博的接口 add_pic_t:必需参数为 content 微博内容,和 pic 微博图片。调用时同样以键值对方式传参。而且,图片是以二进制流的形式上传的。而文档中有关它的接口示例,我始终没找到。最后,我采用了 CURLFIle 类实现图片流上传。

$qc = new QC('你的access_token', '你的openid');

$weibo = [

 'content' => '微博内容',

 'pic' => new CURLFile('要上传的图片路径')

];

$result = $qc->add_pic_t($weibo);

注意到 pic 参数值为 CURLFile 类的实例(图片路径最好是绝对路径)。网上有些资料介绍了 file(image_path) 和 file_get_contents(image_path) 方式设置 pic 参数,但我这里都没有成功(微博发布成功,但没有图片)。

小结

主要的坑就这两个,审核平台问题和微博图片上传问题。以后可能还会用,所以在这里作以记录,备忘。

oAuth 认证与授权

一、什么是OAuth协议

OAuth(开放授权)是一个开放标准。

允许第三方网站在用户授权的前提下访问在用户在服务商那里存储的各种信息。

而这种授权无需将用户提供用户名和密码提供给该第三方网站。

OAuth允许用户提供一个令牌给第三方网站,一个令牌对应一个特定的第三方网站,同时该令牌只能在特定的时间内访问特定的资源。

二、OAuth的原理和授权流程

OAuth的认证和授权的过程中涉及的三方包括:

服务商:用户使用服务的提供方,一般用来存消息、储照片、视频、联系人、文件等(比如Twitter、Sina微波等)。

用 户:服务商的用户

第三方:通常是网站,该网站想要访问用户存储在服务商那里的信息。

比如某个提供照片打印服务的网站,用户想在那里打印自己存在服务商那里的网络相册。

在认证过程之前,第三方需要先向服务商申请第三方服务的唯一标识。

OAuth认证和授权的过程如下:

1、用户访问第三方网站网站,想对用户存放在服务商的某些资源进行操作。

2、第三方网站向服务商请求一个临时令牌。

3、服务商验证第三方网站的身份后,授予一个临时令牌。

4、第三方网站获得临时令牌后,将用户导向至服务商的授权页面请求用户授权,然后这个过程中将临时令牌和第三方网站的返回地址发送给服务商。

5、用户在服务商的授权页面上输入自己的用户名和密码,授权第三方网站访问所相应的资源。

6、授权成功后,服务商将用户导向第三方网站的返回地址。

7、第三方网站根据临时令牌从服务商那里获取访问令牌。

8、服务商根据令牌和用户的授权情况授予第三方网站访问令牌。

9、第三方网站使用获取到的访问令牌访问存放在服务商的对应的用户资源。

三、目前支持OAuth的网站有哪些?

t.sina.com.cn

t.qq.com

t.sohu.com

t.163.com

www.douban.com

www.twitter.com

www.facebook.com

Google Buzz

springboot 封装了oauth2的协议.里面有两个比较常用的接口.

1. 获取token

接口: /oauth/token?

参数: (grant_type是写死的,其它的两个自定义)

完整的样例:http://localhost:9000/oauth/token?grant_type=password&[email protected]&password=oQd-BfT-cer-7LP

返回结果样例:

{

    "access_token": "beeaa54e-8391-4de0-8ba6-ce145b3fb812",

    "token_type": "bearer",

    "refresh_token": "8129769a-d804-46c7-856a-3bacd409b650",

    "expires_in": 3599,

    "scope": "read write"

}

2. 刷新token

接口:http://localhost:9000/oauth/token?

参数:(refresh_token是根据1中的来定的.其它参数是写死的)

  • client_id=dashboard

  • client_secret=secret

  • grant_type=refresh_token

  • refresh_token=43dca105-627e-4f50-86e8-0c22c2f3abe9

样例: http://localhost:9000/oauth/token?client_id=dashboard&client_secret=secret&grant_type=refresh_token&refresh_token=43dca105-627e-4f50-86e8-0c22c2f3abe9

返回结果

{

    "access_token": "0135c92b-12ab-4af9-88f4-97ef85115e71",

    "token_type": "bearer",

    "refresh_token": "75d209b5-a30d-43a8-abcd-850e7fb62e76",

    "expires_in": 3599,

    "scope": "read write"

}

 
 
G
M
T
 
 
Detect languageAfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBengaliBosnianBulgarianCatalanCebuanoChichewaChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDutchEnglishEsperantoEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekGujaratiHaitian CreoleHausaHebrewHindiHmongHungarianIcelandicIgboIndonesianIrishItalianJapaneseJavaneseKannadaKazakhKhmerKoreanLaoLatinLatvianLithuanianMacedonianMalagasyMalayMalayalamMalteseMaoriMarathiMongolianMyanmar (Burmese)NepaliNorwegianPersianPolishPortuguesePunjabiRomanianRussianSerbianSesothoSinhalaSlovakSlovenianSomaliSpanishSundaneseSwahiliSwedishTajikTamilTeluguThaiTurkishUkrainianUrduUzbekVietnameseWelshYiddishYorubaZulu
 
AfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBengaliBosnianBulgarianCatalanCebuanoChichewaChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDutchEnglishEsperantoEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekGujaratiHaitian CreoleHausaHebrewHindiHmongHungarianIcelandicIgboIndonesianIrishItalianJapaneseJavaneseKannadaKazakhKhmerKoreanLaoLatinLatvianLithuanianMacedonianMalagasyMalayMalayalamMalteseMaoriMarathiMongolianMyanmar (Burmese)NepaliNorwegianPersianPolishPortuguesePunjabiRomanianRussianSerbianSesothoSinhalaSlovakSlovenianSomaliSpanishSundaneseSwahiliSwedishTajikTamilTeluguThaiTurkishUkrainianUrduUzbekVietnameseWelshYiddishYorubaZulu
 
 
 
 
 
 
 
 
 
Text-to-speech function is limited to 200 characters
 
 
Options : History : Feedback : Donate Close

猜你喜欢

转载自my.oschina.net/botkenni/blog/1819325