谈谈第三方App接入微信登录 解读


Posted in Javascript onDecember 27, 2016

接入微信登录:

1、准备工作

1.在微信开放平台https://open.weixin.qq.com/注册成为开发者。

2.在“管理中心”中创建一个移动应用,需“应用名称、简介、及28*28和108*108的PNG图片各一张,且大小不超过300k”,点击下一步,需“应用官网地址,应用签名及包名”等信息,然后即可提交审核。

说明:

应用签名:可在微信开发平台的资源中心》》资源下载》》中下载“签名生成工具”,用户获取已经安装到手机的第三方应用的签名。输入应用包名,即可获得该应用的签名值。

3.提交审核后,在7个工作日内腾讯将给出审核结果。(通常较快,几个小时就可反馈结果)

2、微信登录接入

微信登录遵循协议Aouth2.0中的授权码模式,先介绍一下Aouth2.0的流程:

谈谈第三方App接入微信登录 解读

3、微信登录的官方文档将微信登录分为3个步骤:

第一步.请求code:

{
  // send oauth request 
   Final SendAuth.Req req = new SendAuth.Req();
   req.scope = "snsapi_userinfo";
   req.state = "wechat_sdk_demo_test";
   api.sendReq(req);
}

用这段代码向微信开放平台请求授权码code,可拉起微信并打开授权登录页(前提是你安装了微信应用并已登录,未登录的会引导你先登录)下图:

谈谈第三方App接入微信登录 解读

需要注意的情况:

1.如果微信授权页不显示,请检查你的APP签名是否和你在腾讯开放平台的APP签名一致,不一致可修改腾讯开放平台中的APP签名,修改后重装微信或清除微信数据后重试。

2.在你的包名相应目录下新建一个wxapi目录,并在该wxapi目录下新增一个WXEntryActivity类,该类继承自Activity(例如应用程序的包名为net.sourceforge,则新的包名为:net.sourceforge.wxapi),此处应注意包名不要弄错,新增类的名字必须为WXEntryActivity。

返回说明

用户点击授权后,微信客户端会被拉起,跳转至授权界面,用户在该界面点击允许或取消,SDK通过SendAuth的Resp返回数据给调用方。回调WXEntryActivity中的onResp(BaseResp resp)方法,如下:

@Override
public void onResp(BaseResp resp) {
  int errorCode = resp.errCode;
  switch (errorCode) {
  case BaseResp.ErrCode.ERR_OK:
    //用户同意
    String code = ((SendAuth.Resp) resp).code;
    break;
  case BaseResp.ErrCode.ERR_AUTH_DENIED:
    //用户拒绝
    break;
  case BaseResp.ErrCode.ERR_USER_CANCEL:
    //用户取消
    break;
  default:
    break;
  }
  ToastUtil.showMessageLong(this, resp.errStr);
}

客户端收到授权码后,向自己的服务器发起登录请求,并附带收到的授权码。

服务端收到登录请求,向微信开放平台请求获取access_token,微信开放平台返回Json字符串:

第二步:通过code获取access_token:

获取第一步的code后,请求以下链接获取access_token:

private String getAccessToken(String code) {
    String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code";
    URI uri = URI.create(url);
    HttpClient client = new DefaultHttpClient();
    HttpGet get = new HttpGet(uri);
    HttpResponse response;
  try {
    response = client.execute(get);
    if (response.getStatusLine().getStatusCode() == 200) {
      HttpEntity entity = response.getEntity();

      BufferedReader reader = new BufferedReader(new InputStreamReader(entity.getContent(), "UTF-8"));
      StringBuilder sb = new StringBuilder();

      for (String temp = reader.readLine(); temp != null; temp = reader.readLine()) {
        sb.append(temp);
      }

      JSONObject object = new JSONObject(sb.toString().trim());
      accessToken = object.getString("access_token");
      openID = object.getString("openid");
      refreshToken = object.getString("refresh_token");
      expires_in = object.getLong("expires_in");
      return accessToken;
    }
  } catch (Exception e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
  }
  return null;
}

参数说明

参数        是否必须        说明
appid       是        应用唯一标识,在微信开放平台提交应用审核通过后获得

secret      是      应用密钥AppSecret,在微信开放平台提交应用审核通过后获得

code        是       填写第一步获取的code参数

grant_type  是      填authorization_code回说明**

正确的返回:

{ 
"access_token":"ACCESS_TOKEN", 
"expires_in":7200, 
"refresh_token":"REFRESH_TOKEN",
"openid":"OPENID", 
"scope":"SCOPE",
"unionid":"o6_bmasdasdsad6_2sgVt7hMZOPfL"
}

  参数                                  说明
access_token                    接口调用凭证
expires_in  access_token        接口调用凭证超时时间,单位(秒)
refresh_token                   用户刷新access_token
openid                          授权用户唯一标识
scope                           用户授权的作用域,使用逗号(,)分隔
unionid          只有在用户将公众号绑定到微信开放平台帐号后,才会出现该字段。

错误返回样例:

{"errcode":40029,"errmsg":"invalid code"}

第三步:通过access_token调用接口

获取access_token后,进行接口调用,有以下前提:

  • access_token有效且未超时;
  • 微信用户已授权给第三方应用帐号相应接口作用域(scope)。

对于接口作用域(scope),能调用的接口有以下:

授权作用域(scope)             接口                接口说明
snsapi_base       /sns/oauth2/access_token     通过code换取              access_token、refresh_token和已授权scope
                              /sns/oauth2/refresh_token  刷新或续期access_token使用
                                      /sns/auth                  检查access_token有效性
snsapi_userinfo            /sns/userinfo               获取用户个人信息

其中snsapi_base属于基础接口,若应用已拥有其它scope权限,则默认拥有snsapi_base的权限。使用snsapi_base可以让移动端网页授权绕过跳转授权登录页请求用户授权的动作,直接跳转第三方网页带上授权临时票据(code),但会使得用户已授权作用域(scope)仅为snsapi_base,从而导致无法获取到需要用户授权才允许获得的数据和基础功能。

以获取用户信息为例:

private void getUserInfo() {
    if (isAccessTokenIsInvalid() && System.currentTimeMillis() < expires_in) {
      String uri = "https://api.weixin.qq.com/sns/userinfo?access_token=" + accessToken + "&openid=" + openID;
      HttpClient client = new DefaultHttpClient();
      HttpGet get = new HttpGet(URI.create(uri));
      try {
        HttpResponse response = client.execute(get);
        if (response.getStatusLine().getStatusCode() == 200) {
          BufferedReader reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent(), "UTF-8"));
          StringBuilder builder = new StringBuilder();
          for (String temp = reader.readLine(); temp != null; temp = reader.readLine()) {
            builder.append(temp);
          }
          JSONObject object = new JSONObject(builder.toString().trim());
          String nikeName = object.getString("nickname");
        }
      } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      }
    }
  }

微信重复登录

假设用户已经获得授权,则下次登录时只需要验证access_token是否有效,无效则重新获取授权,有效则无需重新获得授权。

1.用户向自己的服务器请求登录,登录方式为微信登录,附带上次登录返回的的access_token

2.服务器收到用户的登录请求,向微信开放平台发送access_token是否有效的验证请求如下:

private boolean isAccessTokenIsInvalid() {
    String url = "https://api.weixin.qq.com/sns/auth?access_token=" + accessToken + "&openid=" + openID;
    URI uri = URI.create(url);
    HttpClient client = new DefaultHttpClient();
    HttpGet get = new HttpGet(uri);
    HttpResponse response;
    try {
      response = client.execute(get);
      if (response.getStatusLine().getStatusCode() == 200) {
        HttpEntity entity = response.getEntity();
      BufferedReader reader = new BufferedReader(new InputStreamReader(entity.getContent(), "UTF-8"));
      StringBuilder sb = new StringBuilder();

      for (String temp = reader.readLine(); temp != null; temp = reader.readLine()) {
        sb.append(temp);
      }
      JSONObject object = new JSONObject(sb.toString().trim());
      int errorCode = object.getInt("errcode");
      if (errorCode == 0) {
        return true;
      }
    }
  } catch (Exception e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
  }
  return false;
}

返回说明

正确的Json返回结果:

{ 
  "errcode":0,"errmsg":"ok"
  }

错误的Json返回示例:

{ 
  "errcode":40003,"errmsg":"invalid openid"
  }

如果access_token有效,服务端将信息返回给客户端,客户端成功登录。

如果access_token无效,服务端向微信开放平台发送刷新access_token的请求如下:

access_token是调用授权关系接口的调用凭证,由于access_token有效期(目前为2个小时)较短,当access_token超时后,可以使用refresh_token进行刷新,access_token刷新结果有两种:

1.若access_token已超时,那么进行refresh_token会获取一个新的access_token,新的超时时间;

2.若access_token未超时,那么进行refresh_token不会改变access_token,但超时时间会刷新,相当于续期access_token。
刷新token

private void refreshAccessToken() {
  String uri = "https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=" + ShareUtil.APP_ID + "&grant_type=refresh_token&refresh_token="
      + refreshToken;
  HttpClient client = new DefaultHttpClient();
  HttpGet get = new HttpGet(URI.create(uri));
  try {
    HttpResponse response = client.execute(get);
    if (response.getStatusLine().getStatusCode() == 200) {
      BufferedReader reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent(), "UTF-8"));
      StringBuilder builder = new StringBuilder();
      for (String temp = reader.readLine(); temp != null; temp = reader.readLine()) {
        builder.append(temp);
      }
      JSONObject object = new JSONObject(builder.toString().trim());
      accessToken = object.getString("access_token");
      refreshToken = object.getString("refresh_token");
      openID = object.getString("openid");
      expires_in = object.getLong("expires_in");
    }
  } catch (Exception e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
  }
}

正确的返回:

{ 
"access_token":"ACCESS_TOKEN", 
"expires_in":7200, 
"refresh_token":"REFRESH_TOKEN", 
"openid":"OPENID", 
"scope":"SCOPE" 
}

参数                    说明
access_token       接口调用凭证
expires_in        access_token接口调用凭证超时时间,单位(秒)
refresh_token     用户刷新access_token
openid           授权用户唯一标识
scope          用户授权的作用域,使用逗号(,)分隔

错误返回样例:

{
"errcode":40030,"errmsg":"invalid refresh_token"
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
学习YUI.Ext第五日--做拖放Darg&amp;Drop
Mar 10 Javascript
js 提交和设置表单的值
Dec 19 Javascript
javascript 获取函数形参个数
Jul 31 Javascript
Node.js的Koa框架上手及MySQL操作指南
Jun 13 Javascript
jQuery基本选择器之标签名选择器
Sep 03 Javascript
jQueryUI Datepicker组件设置日期高亮
Oct 13 Javascript
用headjs来管理和加载js 提高网站加载速度
Nov 29 Javascript
Bootstrap组合上、下拉框简单实现代码
Mar 06 Javascript
Vue路由钩子之afterEach beforeEach的区别详解
Jul 15 Javascript
解决cordova+vue 项目打包成APK应用遇到的问题
May 10 Javascript
Paypal支付不完全指北
Jun 04 Javascript
vue集成openlayers加载geojson并实现点击弹窗教程
Sep 24 Javascript
JavaScript trim 实现去除字符串首尾指定字符的简单方法
Dec 27 #Javascript
修改ligerui 默认确认按钮的方法
Dec 27 #Javascript
js判断一个字符串是以某个字符串开头的简单实例
Dec 27 #Javascript
浅谈Vue的基本应用
Dec 27 #Javascript
利用Angularjs中模块ui-route管理状态的方法
Dec 27 #Javascript
javascript十六进制数字和ASCII字符之间的转换方法
Dec 27 #Javascript
浅谈javascript中的数据类型转换
Dec 27 #Javascript
You might like
提升PHP执行速度全攻略(下)
2006/10/09 PHP
PHP 实现explort() 功能的详解
2013/06/20 PHP
php命令行(cli)下执行PHP脚本文件的相对路径的问题解决方法
2015/05/25 PHP
php文件上传 你真的掌握了吗
2016/11/28 PHP
magento后台无法登录解决办法的两种方法
2016/12/09 PHP
PHP Post获取不到非表单数据的问题解决办法
2018/02/27 PHP
php插入mysql数据返回id的方法
2018/05/31 PHP
对php 判断http还是https,以及获得当前url的方法详解
2019/01/15 PHP
PHP PDOStatement::setAttribute讲解
2019/02/01 PHP
用PHP做了一个领取优惠券活动的示例代码
2019/07/05 PHP
php接口隔离原则实例分析
2019/11/11 PHP
php下的原生ajax请求用法实例分析
2020/02/28 PHP
javascript的trim,ltrim,rtrim自定义函数
2008/09/21 Javascript
jquery 简短右键菜单 多浏览器兼容
2010/01/01 Javascript
javascript 数组学习资料收集
2010/04/11 Javascript
javascript屏蔽右键代码
2014/05/15 Javascript
解决layer.open后laydate失效的问题
2019/09/06 Javascript
vue使用自定义事件的表单输入组件用法详解【日期组件与货币组件】
2020/06/01 Javascript
vue单元格多列合并的实现
2020/11/26 Vue.js
[02:27]《DAC最前线》之附加赛征程
2015/01/29 DOTA
python使用BeautifulSoup与正则表达式爬取时光网不同地区top100电影并对比
2019/04/15 Python
Python语言进阶知识点总结
2019/05/28 Python
Python面向对象之多态原理与用法案例分析
2019/12/30 Python
Tensorflow tf.dynamic_partition矩阵拆分示例(Python3)
2020/02/07 Python
Django框架请求生命周期实现原理
2020/11/13 Python
HTML5 Canvas中绘制椭圆的4种方法
2015/04/24 HTML / CSS
斯凯奇美国官网:SKECHERS美国
2016/08/20 全球购物
英国最大的正宗复古足球衫制造商和零售商:TOFFS
2018/06/21 全球购物
屈臣氏马来西亚官网:Watsons马来西亚
2019/06/15 全球购物
保险内勤岗位职责
2014/04/05 职场文书
2015年小班保育员工作总结
2015/05/27 职场文书
2016初一新生军训心得体会
2016/01/11 职场文书
《小摄影师》教学反思
2016/02/18 职场文书
CSS3实现三角形不断放大效果
2021/04/13 HTML / CSS
python如何进行基准测试
2021/04/26 Python
详解python字符串驻留技术
2021/05/21 Python