谈谈第三方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 相关文章推荐
用javascript实现页面打印的三种方法
Mar 05 Javascript
带左右箭头图片轮播的JS代码
Dec 18 Javascript
javascript伸缩型菜单实现代码
Nov 16 Javascript
js 递归和定时器的实例解析
Feb 03 Javascript
JS闭包的几种常见形式实例详解
Sep 16 Javascript
Koa2 之文件上传下载的示例代码
Mar 29 Javascript
Vue全局loading及错误提示的思路与实现
Aug 09 Javascript
微信小程序实现吸顶效果
Jan 08 Javascript
JavaScript事件循环及宏任务微任务原理解析
Sep 02 Javascript
原生JavaScript实现拖动校验功能
Sep 29 Javascript
四十九个javascript小知识实用技巧
Nov 20 Javascript
Vue操作Storage本地化存储
Apr 29 Vue.js
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
session在php5.3中的变化 session_is_registered() is deprecated in
2013/11/12 PHP
php删除指定目录的方法
2015/04/03 PHP
利用PHP如何实现Socket服务器
2015/09/23 PHP
php使用curl并发减少后端访问时间的方法分析
2016/05/12 PHP
php中使用websocket详解
2016/09/23 PHP
php使用json-schema模块实现json校验示例
2019/09/28 PHP
javascript新手语法小结
2008/06/15 Javascript
一些常用的JS功能函数(2009-06-04更新)
2009/06/04 Javascript
jquery获取ASP.NET服务器端控件dropdownlist和radiobuttonlist生成客户端HTML标签后的value和text值
2010/06/28 Javascript
JS继承 笔记
2011/07/13 Javascript
jquery批量设置属性readonly和disabled的方法
2014/01/24 Javascript
JavaScript利用构造函数和原型的方式模拟C#类的功能
2014/03/06 Javascript
使用Jquery实现每日签到功能
2015/04/03 Javascript
javascript中call,apply,bind函数用法示例
2016/12/19 Javascript
EasyUI折叠表格层次显示detailview详解及实例
2016/12/28 Javascript
bootstrap侧边栏圆点导航
2017/01/11 Javascript
解决html-jquery/js引用外部图片时遇到看不了或出现403的问题
2017/09/22 jQuery
React组件中的this的具体使用
2018/02/28 Javascript
在layui tab控件中载入外部html页面的方法
2019/09/04 Javascript
浅谈layui 表单元素的选中问题
2019/10/25 Javascript
js函数和this用法实例分析
2020/03/13 Javascript
浅谈Vue使用Cascader级联选择器数据回显中的坑
2020/10/31 Javascript
[01:23:45]DOTA2-DPC中国联赛 正赛 CDEC vs Dragon BO3 第一场 1月22日
2021/03/11 DOTA
python迭代器的使用方法实例
2013/11/21 Python
python实现模拟按键,自动翻页看u17漫画
2015/03/17 Python
python使用xpath中遇到:到底是什么?
2018/01/04 Python
Python爬取12306车次信息代码详解
2020/08/12 Python
python压包的概念及实例详解
2021/02/17 Python
实现CSS3中的border-radius(边框圆角)示例代码
2013/07/19 HTML / CSS
Keds加拿大官网:购买帆布运动鞋和皮鞋
2019/09/26 全球购物
小学生新学期寄语
2014/01/19 职场文书
大学军训感言1000字
2014/02/25 职场文书
求职自我推荐信
2014/06/25 职场文书
见习报告格式要求
2014/11/04 职场文书
2014年施工员工作总结
2014/11/18 职场文书
2019年销售人员的职业生涯规划书
2019/03/25 职场文书