谈谈第三方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脚本
Nov 01 Javascript
Javascript 读取操作Sql中的Xml字段
Oct 09 Javascript
JavaScript实现twitter puddles算法实例
Dec 06 Javascript
Javascript 运动中Offset的bug解决方案
Dec 24 Javascript
Bootstrap3.0学习教程之JS折叠插件
May 27 Javascript
原生JS实现导航下拉菜单效果
Nov 25 Javascript
详解用node-images 打造简易图片服务器
May 08 Javascript
原生js FileReader对象实现图片上传本地预览效果
Mar 27 Javascript
JS中关于正则的巧妙操作
Aug 31 Javascript
详解Nuxt.js中使用Element-UI填坑
Sep 06 Javascript
JS实现拼图游戏
Jan 29 Javascript
vue更改数组中的值实例代码详解
Feb 07 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 session劫持和防范的方法
2013/11/12 PHP
php readfile()修改文件上传大小设置
2017/08/11 PHP
Laravel 5.1 框架Blade模板引擎用法实例分析
2020/01/04 PHP
Maps Javascript
2007/01/22 Javascript
CutePsWheel javascript libary 控制输入文本框为可使用滚轮控制的js库
2010/02/07 Javascript
javascript中length属性的探索
2011/07/31 Javascript
JS控件的生命周期介绍
2012/10/22 Javascript
JavaScript调用后台的三种方法实例
2013/10/17 Javascript
jQuery选择器querySelector的使用指南
2015/01/23 Javascript
jquery通过closest选择器修改上级元素的方法
2015/03/17 Javascript
jQuery实现的跨容器无缝拖动效果代码
2016/06/21 Javascript
JS查找英文文章中出现频率最高的单词
2017/03/20 Javascript
AngularJs ng-change事件/指令的用法小结
2017/11/01 Javascript
微信小程序实现YDUI的ScrollNav组件
2018/02/02 Javascript
mpvue写一个CPASS小程序的示例
2018/09/04 Javascript
详解element-ui日期时间选择器的日期格式化问题
2019/04/08 Javascript
JavaScript实现简单计算器功能
2019/12/19 Javascript
JS常见错误(Error)及处理方案详解
2020/07/02 Javascript
python正则表达式判断字符串是否是全部小写示例
2013/12/25 Python
Python程序中的观察者模式结构编写示例
2016/05/27 Python
如何使用VSCode愉快的写Python于调试配置步骤
2018/04/06 Python
python时间序列按频率生成日期的方法
2019/05/14 Python
500行Python代码打造刷脸考勤系统
2019/06/03 Python
python将时分秒转换成秒的实例
2019/12/07 Python
使用 Python 合并多个格式一致的 Excel 文件(推荐)
2019/12/09 Python
websocket+sockjs+stompjs详解及实例代码
2018/11/30 HTML / CSS
StudentUniverse英国:学生航班、酒店和旅游
2019/08/25 全球购物
简述安装Slackware Linux系统的过程
2012/05/08 面试题
运动会入场词100字
2014/02/06 职场文书
司仪主持词两篇
2014/03/22 职场文书
竞聘书怎么写,如何写?
2014/03/31 职场文书
三八妇女节标语
2014/10/09 职场文书
金秋助学感谢信
2015/01/21 职场文书
事业单位财务人员岗位职责
2015/04/14 职场文书
vue-cli4.5.x快速搭建项目
2021/05/30 Vue.js
React如何创建组件
2021/06/27 Javascript