完美利用Yii2微信后台开发的系列总结【蒲京娱乐场网站】

李秉骏:在Phonegap下实现oAuth认证

2012/07/18 · HTML5 · 2
评论
· 来源:
李秉骏     ·
HTML5

本文由李秉骏(@CashLee李秉骏)投稿于伯乐在线,也欢迎其他朋友投稿。提示:投稿时记得留下微博账号哦 蒲京娱乐场网站 1

前段时间做过两次关于Phonegap的现场交流会议分享。基本上把Phonegap的一些特性和大家交流了一下,大家对于Phonegap的
兴趣也是非常多的。但是因为Phonegap相对于原生应用来说,只有一个View,这个View就是一个Web的容器,这使得Phonegap就存在很
多限制。其中一部分的限制我们已经通过HTML5的API以及Phonegap为我们搭建的桥去实现了,另外一部分我们就得通过Phonegap
plugins来实现,而实际上我个人认为Phonegap最强大的地方也在于有那么大的一个群体在为他提供各种各样的Plugins,以便去应对实际项
目中遇到的问题。

我记得在和大家交流的时候大家经常会问Phonegap如何做本地的缓存啊(WebSQL),如何贴近原生应用(这个涉及到架构,界面渲染问题,这
里我也不好深入讲,毕竟不是本文要讨论的内容),还有一个很头疼的问题就是如果要做一个开放平台的应用,如何实现oAuth认证。此前我也遇到过类似的一
些情况,当我再次遇到这个棘手的问题的时候,我相信一定也有Phonegap的粉丝遇到类似的情况的。于是我就总结下来何大家探讨一下如何解决这个问题
吧。

首先目标:解决oAuth认证。

制定计划:1.
知道oAuth原理;2.了解Phonegap在处理这个问题时候的运行机制;3.
制定计划实现代码。

下面我们就来一步一步地分析,看如何解决这个情况吧。(因为我在项目中遇到的是腾讯微博开放平台的oAuth认证,那么下面我就用腾讯oAuth认证为例吧)

关于oAuth认证,相信做过开放平台应用的朋友都已经非常熟悉了,如果你还没有做过或者对于oAuth认证流程非常不了解,那么我建议你先了解一
下原理,在这里我不希望花太多的篇幅去介绍这个东西,因为在很多地方都可以找到,下面我推荐两个地址方便大家去阅读,一定要阅读,这会对你理解下面的文章
有莫大的帮助的。

腾讯微博开放平台:http://wiki.open.t.qq.com/index.php/OAuth2.0%E9%89%B4%E6%9D%83

新浪微博开放平台:http://open.weibo.com/wiki/Oauth2

当然在这里上面需要阐述说明的是oAuth认证机制是一个通用的手法,但是因为每个开放平台有自己的政策,因此可能在其中稍有改变,而且最终获得的权限也会各不相同。而最近新浪微博实在太多坑爹的事情了,实在忍受不了,于是我转战到腾讯的平台了。

好的,如果你看完了oAuth认证的流程,就直接到这里来。众所周知,在oAuth认证的流程中,有一个授权页面,而这个授权页面是通过开放平台提供的,具体的样式见下图:

蒲京娱乐场网站 2

这个页面用于输入开放平台的帐户以及密码,通过授权获取响应的openid以及openkey,最终换取access-token(待会我会结合腾讯微博oAuth认证流程的特点,以及代码和大家分析的)。

这个页面是弹出的,如果在Phonegap里面做的话会很奇怪:1,因为属于弹窗,在Phonegap中本身就是一个WebView如果你还弹的话
就会飞到了Safari的浏览器中,这就跳出应用本身,跳出去认证还有戏吗?2,通过iFrame,首先体验非常不好,其次iFrame本身又属于跨域的
问题,这就不好解决了(为什么体验不好呢,主要是因为授权页面的样式是不固定的,类似腾讯微博开放平台,就比新浪的授权页面做得差,根本不和手机匹配的,
而且有些做得好的,认证页宽度就是320px,就占了你整个应用的版面,体验很不好)那么Phonegap中该如何实现呢?

带着问题,我们就希望在Phonegap中再度引入一个WebView。刚刚提到Phonegap的强大还在于很多人以及官方的团队,为其提供了一
套很好的插件机制,以解决各种各样的需要。在Phonegap中有一个插件叫做ChildBrowser,顾名思义就是:子浏览器。(其实我在上两次的
Phonegap专题技术分享中以及提及到让大家用这个东西去解决,不过当时分享时间有限只能够草率带过,抱歉)子浏览器的作用其实就是让你在
Phonegap应用内部调起一个浏览器的View,让你进行pdf,图片,视频,甚至网页阅读的工具。(实际上你看我上面的截图,就是用
ChildBrowser来实现的)这就好了,这就可以让你调起浏览器而且不跳出应用本身了,可以很好地解决oAuth认证的问题。
ChildBrowser下载地址:

https://github.com/phonegap/phonegap-plugins/tree/master/iOS/ChildBrowser

在地址上面,你应该已经看到ChildBrowser的安装方法以及使用方法了,非常简单,真正的即插即用。如果你觉得英文太难,这我就帮不了你
了,你就自行Google翻译一下吧。相信你很快就可以做出一个ChildBrowser的Demo的。在这个地址上面,其实你返回上一层目录,其实你也
已经看到各式各样的Phonegap
Plugins,通过这些东西,你还可以调用起手机内部更多有趣的资源的!这个就要靠你自己去发掘啦!(其他平台的应用也有相应的插件的Android开
发者不要骂果粉哦!)

https://github.com/phonegap/phonegap-plugins/tree/master/iOS

好了慢慢地我们就要涉及到代码部分了。首先我们看看调用ChildBrowser的Javascript代码:

JavaScript

cb = window.plugins.childBrowser; /* if(cb != null) {
cb.onLocationChange = function(loc){ root.locChanged(loc);
};//地址发生改变时候执行的函数 cb.onClose =
function(){root.onCloseBrowser(); };//通过js关闭ChildBrowser的办法
cb.onOpenExternal = function(){root.onOpenExternal(); }; */
cb.showWebPage(“http://google.com“);

1
2
3
4
5
6
7
8
        cb = window.plugins.childBrowser;
/*
        if(cb != null) {
        cb.onLocationChange = function(loc){ root.locChanged(loc); };//地址发生改变时候执行的函数
        cb.onClose = function(){root.onCloseBrowser(); };//通过js关闭ChildBrowser的办法
        cb.onOpenExternal = function(){root.onOpenExternal(); };
*/
        cb.showWebPage("http://google.com");

其中cb就是初始化的ChildBrowser,而showWebPage就是调起这个页面的方法。可见代码中要打开的网址就是
Google.com啦,这个地球人都能够看得懂了。于是我们就可以马上想到我们要用ChildBrowser打开的网址是我们在网上指定的应用授权站点
了。而我是部署在SAE上面的,所以下面的例子也用PHP来说吧,期待语言也是相同的道理,转义就可以了。在说代码之前,我们先来说说具体通讯的流程,以
及我们接下来要达到的目标。

蒲京娱乐场网站 3
在这里,我们的手机端是通过访问SAE服务器,由SAE服务器管理数据并与腾讯微博开放平台通讯的,这里手机端并没有直接和腾讯微博开放平台通讯(我这样
处理的原因是1,方便在服务器端管理帐户,这样的话可以观察自己的应用的帐户状况;2,服务器端实现推送机制,方便管理token以及做api;3,服务
器端还可以和其他开放平台帐户绑定)。因此,我们的整套认证方案会在服务器端完成。

而根据腾讯微博开放平台,我们首先会在开放平台上面注册自己的应用,注册的流程以及办法我不说了,注册的地址是:http://dev.open.t.qq.com/development/,注册你的应用后,你相应能够获得的东西是:

JavaScript

应用名称:mobile_test_api 应用类型:客户端应用 App Key:88888888 App
Secret:ainidenideiienfeomeomroemrome

1
2
3
4
应用名称:mobile_test_api
应用类型:客户端应用
App Key:88888888
App Secret:ainidenideiienfeomeomroemrome

在这里我的App key以及App
Secret是假的(你懂的,你应该有你自己的),下面我们就使用腾讯提供给我们的PHP
SDK,下载地址:http://wiki.open.t.qq.com/index.php/SDK%E4%B8%8B%E8%BD%BD。有了SDK后我们就可以把SDK放到自己的环境上面,然后配置服务器端的代码了。下图是我简单配置的服务端的代码,lib下存放的就是腾讯微博的sdk。当然实际生产环境和这个有不同。这里仅仅作为演示使用:

蒲京娱乐场网站 4

下面就根据腾讯微博认证的流程,逐一讲解一下这些文件以及内部的代码吧。

index.php

PHP

<?php require_once ‘app_config.php’;
$url=”https://open.t.qq.com/cgi-bin/oauth2/authorize?client\_id=".$client\_id."&APP\_KEY=".$app\_key."&wap=2&response\_type=code&redirect\_uri=http://yoururl.com/get\_auth.php";//指定URL地址
header(‘Location:’.$url);

1
2
3
4
5
6
<?php
require_once ‘app_config.php’;
 
$url="https://open.t.qq.com/cgi-bin/oauth2/authorize?client_id=".$client_id."&APP_KEY=".$app_key."&wap=2&response_type=code&redirect_uri=http://yoururl.com/get_auth.php";//指定URL地址
 
header(‘Location:’.$url);

这里引入的app_config.php

PHP

<?php $client_id = ‘8888888888’; $app_key =
‘anienineiienrieireowq2839289’;

1
2
3
4
5
<?php
 
$client_id = ‘8888888888’;
 
$app_key = ‘anienineiienrieireowq2839289’;

因为根据腾讯微博开放平台,我们第一步要获取的是Code,如下所述,我们要做的就是做好配置,获取这个Code

JavaScript

第一步:请求code 请求方法: GET 请求地址:
https://open.t.qq.com/cgi-bin/oauth2/authorize?client\_id=APP\_KEY&amp;response\_type=code&amp;redirect\_uri=http://www.myurl.com/example
返回结果:
如果授权成功,授权服务器会将用户的浏览器重定向到redirect_uri,并带上code,openid和openkey等参数,重定向的url如下:
http://www.myurl.com/example?code=CODE&amp;openid=OPENID&amp;openkey=OPENKEY

1
2
3
4
5
6
7
8
9
10
11
12
13
第一步:请求code
 
请求方法:
GET
 
请求地址:
 
https://open.t.qq.com/cgi-bin/oauth2/authorize?client_id=APP_KEY&response_type=code&redirect_uri=http://www.myurl.com/example
 
返回结果:
如果授权成功,授权服务器会将用户的浏览器重定向到redirect_uri,并带上code,openid和openkey等参数,重定向的url如下:
 
http://www.myurl.com/example?code=CODE&openid=OPENID&openkey=OPENKEY

具体需要请求附带的参数,必须要按照oAuth2.0鉴权的页面提示的进行。(http://wiki.open.t.qq.com/index.php/OAuth2.0%E9%89%B4%E6%9D%83

然后我们再来看看我们所配置的文件:

get_auth.php

PHP

<?php require_once ‘app_config.php’; $code = $_REQUEST[‘code’];
$openid = $_REQUEST[‘openid’]; $openkey = $_REQUEST[‘openkey’];
$url =
https://open.t.qq.com/cgi-bin/oauth2/access\_token?client\_id=".$client\_id."&client\_secret=".$app\_key."&grant\_type=authorization\_code&code=".$code."&redirect\_uri=http://yoururl.com/get\_auth.php“;
$message = file_get_contents($url); /* success to print the access
token message */ $access = explode(“=”,$message); print_r(“<br
/>”); $access_message = explode(“&”,$access[1]); $access_token =
$access_message[0]; $user_name = $access[4];
print_r($access_token .” ” . $user_name);

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
<?php
 
require_once ‘app_config.php’;
 
$code = $_REQUEST[‘code’];
 
$openid = $_REQUEST[‘openid’];
 
$openkey = $_REQUEST[‘openkey’];
 
$url = "https://open.t.qq.com/cgi-bin/oauth2/access_token?client_id=".$client_id."&client_secret=".$app_key."&grant_type=authorization_code&code=".$code."&redirect_uri=http://yoururl.com/get_auth.php";
 
$message = file_get_contents($url);
 
/* success to print the access token message */
 
$access = explode("=",$message);
 
print_r("<br />");
 
$access_message = explode("&",$access[1]);
 
$access_token = $access_message[0];
 
$user_name = $access[4];
 
print_r($access_token ."   " . $user_name);

其实到以上为止,我们的配置文件已经弄好了。在这个配置文件中,实际上我们要做的就是腾讯微博开放平台中提及的第二步:

JavaScript

第二步:请求accesstoken 请求地址:
https://open.t.qq.com/cgi-bin/oauth2/access\_token?client\_id=APP\_KEY&amp;client\_secret=APP\_SECRET&amp;redirect\_uri=http://www.myurl.com/example&amp;grant\_type=authorization\_code&amp;code=CODE
返回结果: 返回字符串:
access_token=ACCESS_TOKEN&expires_in=60&refresh_token=REFRESH_TOKEN

1
2
3
4
5
6
7
8
9
第二步:请求accesstoken
 
请求地址:
 
https://open.t.qq.com/cgi-bin/oauth2/access_token?client_id=APP_KEY&client_secret=APP_SECRET&redirect_uri=http://www.myurl.com/example&grant_type=authorization_code&code=CODE
 
返回结果:
返回字符串:
access_token=ACCESS_TOKEN&amp;expires_in=60&amp;refresh_token=REFRESH_TOKEN

如果你现在已经配置好你的服务端口,已经配置好手机端的ChildBrowser,你就已经可以在手机上面看看整个认证的流程了。现在的工作已经完
成了大部分了,不过细心的朋友可能会发现,对啊,认证是完成了,手机上还是没有获得授权啊,因为授权后的信息还不能够通过手机去获取。不要
急,ChildBrowser有趣的地方还没有完呢。在手机端上面我们完成了oAuth认证,总有一些参数返回,不管accesstoken是否存在手机
端,你总得有个帐户机制和服务端通讯。我的服务端在SAE上面,我就建立一个唯一id给手机,于是我就建立了一个帐户机制,存在服务端上,服务端上存储的东西是:

MySQL

CREATE TABLE IF NOT EXISTS `auth_user` ( `id` int(10) NOT NULL
AUTO_INCREMENT, `muser` varchar(255) COLLATE utf8_unicode_ci NOT
NULL, `access_token` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`openid` varchar(255) COLLATE utf8_unicode_ci NOT NULL, `openkey`
varchar(255) COLLATE utf8_unicode_ci NOT NULL, `name` varchar(255)
COLLATE utf8_unicode_ci NOT NULL, `create_time` timestamp NOT NULL
DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT
CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1 ;

1
2
3
4
5
6
7
8
9
10
CREATE TABLE IF NOT EXISTS `auth_user` (
  `id` int(10) NOT NULL AUTO_INCREMENT,
  `muser` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `access_token` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `openid` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `openkey` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1 ;

其实这个表也还没有完善,我必须还要纪录这个用户是否在线(如果有推送机制)。此后手机端和服务端通讯就通过上面的id以及token等的信息进行
通讯,再通过服务端想腾讯微博进行api的通讯,获取我们想要的信息。那么认证后我们通过什么途径拿到认证后返回的信息呢?大家看看上面JS控制
ChildBrowser的代码。会发现里面有一个方法:

JavaScript

cb.onLocationChange = function (loc){ console.warn(loc); };

1
cb.onLocationChange = function (loc){ console.warn(loc); };

如果你在xCode上面跑这段代码的话,你会发现loc打出来的是每次ChildBrowser里面浏览的网页改变的地址。这个时候我们就可以顺水
推舟,根据这里提供的办法,用url的方式把地址返回到Phonegap负责逻辑处理的JS代码中,同时将相关需要通讯的信息也返回。返回后还可以通过回
调的方式执行关闭ChildBrowser的代码:

JavaScript

cb.close();

1
cb.close();

当然,你还可以执行更多异步请求的代码。至于说还可以通过怎么样的方式进行通讯其实还有很多办法,我这里仅仅是提供一下思路引导以及方法。具体的
话,还要实践出真理论,做到非常安全的通讯还值得我们继续深入探讨。那么我要介绍的大概就到这里为止。因为实际项目中我们还有push
notification的机制,所以此后我应该还会联同@Jeff_Kit
http://www.jeffkit.info/
实现一下Phonegap的推送方案,并整理出sdk,成文后开放出来方便大家交流。

对于本文如果有什么疑问或者建议都可以直接向我反馈,我的新浪微博是:@CashLee李秉骏 ,我还经常分享一些代码片段在github上面(开源的精力不多,所以开源项目较少,希望日后增加吧。)我的Github账号
欢迎您和我随时进行交流,也希望Phonegap的中国开发者社区会变得越来越精彩。

注意:ChildBrowser控件在实际环境中因为安全问题可能需要修改,通讯过程中参数也建议加密。:-)

 

本文由李秉骏(@CashLee李秉骏)投稿于伯乐在线,也欢迎其他朋友投稿。提示:投稿时记得留下微博账号哦 蒲京娱乐场网站 5

【如需转载,请标注并保留原文链接和作者等信息,谢谢合作!】

 

 

1 赞 收藏 2
评论

蒲京娱乐场网站 6

网上有很多关于YII2.0微信开发教程,但是太过复杂凌乱,所以今天在这里给大家整理总结利用Yii2微信后台开发的系列了,给需要的小伙伴们参考。

一:接入微信

Yii2后台配置

1.在app/config/params.php中配置token参数

return [
 //微信接入
 'wechat' =>[
 'token' => 'your token',
 ],
];

2.在app/config/main.php中配置路由

因为接口模块使用的RESTful API,所以需要定义路由规则。

'urlManager' => [
 'enablePrettyUrl' => true,
 'enableStrictParsing' => true,
 'showScriptName' => false,
 'rules' => [
 [
  'class' => 'yii\rest\UrlRule',
  'controller' => 'wechat',
  'extraPatterns' => [
  'GET valid' => 'valid',
  ],
 ],
 ],
],

3.在app/controllers中新建WechatController

<?php

namespace api\controllers;

use Yii;
use yii\rest\ActiveController;

class WechatController extends ActiveController
{

 public $modelClass = '';

 public function actionValid()
 {
 $echoStr = $_GET["echostr"];
 $signature = $_GET["signature"];
 $timestamp = $_GET["timestamp"];
 $nonce = $_GET["nonce"];
 //valid signature , option
 if($this->checkSignature($signature,$timestamp,$nonce)){
  echo $echoStr;
 }
 }

 private function checkSignature($signature,$timestamp,$nonce)
 {
 // you must define TOKEN by yourself
 $token = Yii::$app->params['wechat']['token'];
 if (!$token) {
  echo 'TOKEN is not defined!';
 } else {
  $tmpArr = array($token, $timestamp, $nonce);
  // use SORT_STRING rule
  sort($tmpArr, SORT_STRING);
  $tmpStr = implode( $tmpArr );
  $tmpStr = sha1( $tmpStr );

  if( $tmpStr == $signature ){
  return true;
  }else{
  return false;
  }
 }
 }

}

微信公众号后台配置

在微信公众号后台配置URL和Token,然后提交验证即可。

URL:http://app.demo.com/wechats/valid
Token:your token

二:获取用户信息

用户表设计

复制代码 代码如下:

CREATE TABLE `wechat_user` (
蒲京娱乐场网站,  `id` int(11) NOT NULL,
  `openid` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `nickname` varchar(50) COLLATE utf8_unicode_ci NOT NULL COMMENT
‘微信昵称’,
  `sex` tinyint(4) NOT NULL COMMENT ‘性别’,
  `headimgurl` varchar(255) COLLATE utf8_unicode_ci NOT NULL COMMENT
‘头像’,
  `country` varchar(50) COLLATE utf8_unicode_ci NOT NULL COMMENT
‘国家’,
  `province` varchar(50) COLLATE utf8_unicode_ci NOT NULL COMMENT
‘省份’,
  `city` varchar(50) COLLATE utf8_unicode_ci NOT NULL COMMENT
‘城市’,
  `access_token` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `refresh_token` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8
COLLATE=utf8_unicode_ci;
ALTER TABLE `wechat_user`
  ADD PRIMARY KEY (`id`);

获取用户信息的相关接口

1.用户授权接口:获取access_token、openId等;获取并保存用户资料到数据库

复制代码 代码如下:

public function actionAccesstoken()
{
    $code = $_GET[“code”];
    $state = $_GET[“state”];
    $appid = Yii::$app->params[‘wechat’][‘appid’];
    $appsecret = Yii::$app->params[‘wechat’][‘appsecret’];
    $request_url =
https://api.weixin.qq.com/sns/oauth2/access\_token?appid='.$appid.'&secret='.$appsecret.'&code='.$code.'&grant\_type=authorization\_code‘;
    //初始化一个curl会话
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $request_url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    $result = curl_exec($ch);
    curl_close($ch);
    $result = $this->response($result);
    //获取token和openid成功,数据解析
    $access_token = $result[‘access_token’];
    $refresh_token = $result[‘refresh_token’];
    $openid = $result[‘openid’];
    //请求微信接口,获取用户信息
    $userInfo = $this->getUserInfo($access_token,$openid);
    $user_check =
WechatUser::find()->where([‘openid’=>$openid])->one();
    if ($user_check) {
        //更新用户资料
    } else {
        //保存用户资料
    }
    //前端网页的重定向
    if ($openid) {
        return $this->redirect($state.$openid);
    } else {
        return $this->redirect($state);
    }
}

2.从微信获取用户资料

复制代码 代码如下:

public function getUserInfo($access_token,$openid)
{
    $request_url =
https://api.weixin.qq.com/sns/userinfo?access\_token='.$access\_token.'&openid='.$openid.'&lang=zh\_CN‘;
    //初始化一个curl会话
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $request_url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    $result = curl_exec($ch);
    curl_close($ch);
    $result = $this->response($result);
    return $result;
}

3.获取用户资料接口