谈谈第三方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 相关文章推荐
IE 条件注释详解总结(附实例代码)
Aug 29 Javascript
js 如何实现对数据库的增删改查
Nov 23 Javascript
js清理Word格式示例代码
Feb 13 Javascript
使用JavaScript判断图片是否加载完成的三种实现方式
May 04 Javascript
Jquery树插件zTree用法入门教程
Feb 17 Javascript
jquery结婚电子请柬特效源码分享
Aug 21 Javascript
使用jquery实现鼠标滑过弹出更多相关信息层附源码下载
Nov 23 Javascript
一款简单的jQuery图片标注效果附源码下载
Mar 22 Javascript
jquery实用技巧之输入框提示语句
Jul 28 Javascript
jQuery用户头像裁剪插件cropbox.js使用详解
Jun 07 jQuery
AngularJS 的$timeout服务示例代码
Sep 21 Javascript
解决vue打包css文件中背景图片的路径问题
Sep 03 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数组函数
2008/08/18 PHP
深入理解:单一入口、MVC、ORM、CURD、ActiveRecord概念
2013/06/06 PHP
php实现图片添加水印功能
2014/02/13 PHP
php is_writable判断文件是否可写实例代码
2016/10/13 PHP
PHP实现的常规正则验证helper公共类完整实例
2017/04/27 PHP
CI框架实现创建自定义类库的方法
2018/12/25 PHP
深入理解JavaScript系列(7) S.O.L.I.D五大原则之开闭原则OCP
2012/01/15 Javascript
js将当前时间格式转换成时间搓(自写)
2013/09/26 Javascript
Egret引擎开发指南之发布项目
2014/09/03 Javascript
jQuery实现类似老虎机滚动抽奖效果
2015/08/06 Javascript
JavaScript中的跨浏览器事件操作的基本方法整理
2016/05/20 Javascript
AngularJS实践之使用ng-repeat中$index的注意点
2016/12/22 Javascript
实例分析JS与Node.js中的事件循环
2017/12/12 Javascript
vue.js数据绑定操作详解
2018/04/23 Javascript
Vue组件之极简的地址选择器的实现
2018/05/31 Javascript
vue模块拖拽实现示例代码
2019/03/09 Javascript
Electron-vue开发的客户端支付收款工具的实现
2019/05/24 Javascript
JS实现简易留言板增删功能
2020/02/08 Javascript
微信小程序实现时间戳格式转换
2020/07/20 Javascript
Vue 中使用lodash对事件进行防抖和节流操作
2020/07/26 Javascript
Python获取当前时间的方法
2014/01/14 Python
Pyspider中给爬虫伪造随机请求头的实例
2018/05/07 Python
pygame游戏之旅 添加碰撞效果的方法
2018/11/20 Python
浅谈pycharm的xmx和xms设置方法
2018/12/03 Python
把JSON数据格式转换为Python的类对象方法详解(两种方法)
2019/06/04 Python
python通过nmap扫描在线设备并尝试AAA登录(实例代码)
2019/12/30 Python
python 读取.nii格式图像实例
2020/07/01 Python
详解Pycharm与anaconda安装配置指南
2020/08/25 Python
Python私有属性私有方法应用实例解析
2020/09/15 Python
支票、地址标签、包装纸和慰问卡:Current Catalog
2018/01/30 全球购物
商务英语专业求职信
2014/06/26 职场文书
房地产经营管理专业自荐信
2014/09/02 职场文书
2014年小学生迎国庆65周年演讲稿
2014/09/27 职场文书
初三学生语文考试作弊检讨书
2014/12/14 职场文书
幼儿园中秋节活动总结
2015/03/23 职场文书
Python趣味挑战之教你用pygame画进度条
2021/05/31 Python