zoukankan      html  css  js  c++  java
  • 详解如何进行第三方App接入微信登录

    微信登录接入

    微信登录遵循协议Aouth2.0中的授权码模式

    我们来看一下Aouth2.0中的授权码模式是怎么定义的:

    授权码模式(authorization code)是功能最完整、流程最严密的授权模式。它的特点就是通过客户端的后台服务器,与”服务提供商”的认证服务器进行互动。 
    它的步骤如下:

    (A)用户访问客户端,后者将前者导向认证服务器。

    (B)用户选择是否给予客户端授权。

    (C)假设用户给予授权,认证服务器将用户导向客户端事先指定的”重定向URI”(redirection URI),同时附上一个授权码。

    (D)客户端收到授权码,附上早先的”重定向URI”,向认证服务器申请令牌。这一步是在客户端的后台的服务器上完成的,对用户不可见。

    (E)认证服务器核对了授权码和重定向URI,确认无误后,向客户端发送访问令牌(access token)和更新令牌(refresh token)

    第一步.请求code

    1
    2
    3
    4
    5
    6
    7
    {
        // send oauth request
         Final SendAuth.Req req = new SendAuth.Req();
         req.scope = "snsapi_userinfo";
         req.state = "wechat_sdk_demo_test";
         api.sendReq(req);
        }

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

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

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

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

    复制代码
     1 @Override
     2     public void onResp(BaseResp resp) {
     3         int errorCode = resp.errCode;
     4         switch (errorCode) {
     5         case BaseResp.ErrCode.ERR_OK:
     6             //用户同意
     7             String code = ((SendAuth.Resp) resp).code;
     8             break;
     9         case BaseResp.ErrCode.ERR_AUTH_DENIED:
    10             //用户拒绝
    11             break;
    12         case BaseResp.ErrCode.ERR_USER_CANCEL:
    13             //用户取消
    14             break;
    15         default:
    16             break;
    17         }
    18         ToastUtil.showMessageLong(this, resp.errStr);
    19     }
    复制代码

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

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

    第二步:通过code获取access_token(在自己服务器端做)

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

    https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code

    复制代码
     1 private String getAccessToken(String code) {
     2         String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code";
     3         URI uri = URI.create(url);
     4         HttpClient client = new DefaultHttpClient();
     5         HttpGet get = new HttpGet(uri);
     6 
     7         HttpResponse response;
     8         try {
     9             response = client.execute(get);
    10             if (response.getStatusLine().getStatusCode() == 200) {
    11                 HttpEntity entity = response.getEntity();
    12 
    13                 BufferedReader reader = new BufferedReader(new InputStreamReader(entity.getContent(), "UTF-8"));
    14                 StringBuilder sb = new StringBuilder();
    15 
    16                 for (String temp = reader.readLine(); temp != null; temp = reader.readLine()) {
    17                     sb.append(temp);
    18                 }
    19 
    20                 JSONObject object = new JSONObject(sb.toString().trim());
    21                 accessToken = object.getString("access_token");
    22                 openID = object.getString("openid");
    23                 refreshToken = object.getString("refresh_token");
    24                 expires_in = object.getLong("expires_in");
    25                 return accessToken;
    26             }
    27         } catch (ClientProtocolException e) {
    28             // TODO Auto-generated catch block 
    29             e.printStackTrace();
    30         } catch (IOException e) {
    31             // TODO Auto-generated catch block
    32             e.printStackTrace();
    33         } catch (IllegalStateException e) {
    34             // TODO Auto-generated catch block
    35             e.printStackTrace();
    36         } catch (JSONException e) {
    37             // TODO Auto-generated catch block
    38             e.printStackTrace();
    39         }
    40 
    41         return null;
    42     }
    复制代码

    参数说明

    参数        是否必须        说明 
    appid       是        应用唯一标识,在微信开放平台提交应用审核通过后获得
    
    secret      是        应用密钥AppSecret,在微信开放平台提交应用审核通过后获得
    
    code        是        填写第一步获取的code参数
    
    grant_type  是        填authorization_code回说明**
    

    正确的返回:

    复制代码
    1 { 
    2 "access_token":"ACCESS_TOKEN", 
    3 "expires_in":7200, 
    4 "refresh_token":"REFRESH_TOKEN",
    5 "openid":"OPENID", 
    6 "scope":"SCOPE",
    7 "unionid":"o6_bmasdasdsad6_2sgVt7hMZOPfL"
    8 }
    复制代码
     参数                              说明
    access_token                    接口调用凭证
    expires_in  access_token        接口调用凭证超时时间,单位(秒)
    refresh_token                   用户刷新access_token
    openid                          授权用户唯一标识
    scope                           用户授权的作用域,使用逗号(,)分隔
    unionid                         只有在用户将公众号绑定到微信开放平台帐号后,才会出现该字段。


    服务端收到返回的access_token,将access_token,expires_in,access_token是否有效 等数据返回给客户端,客户端成功登录

    客户端可利用已有的access_token获取微信用户信息

    第三步:通过access_token调用接口

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

    1. access_token有效且未超时;
    2. 微信用户已授权给第三方应用帐号相应接口作用域(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,从而导致无法获取到需要用户授权才允许获得的数据和基础功能。

    以获取用户信息为例:
    复制代码
     1 private void getUserInfo() {
     2         if (isAccessTokenIsInvalid() && System.currentTimeMillis() < expires_in) {
     3             String uri = "https://api.weixin.qq.com/sns/userinfo?access_token=" + accessToken + "&openid=" + openID;
     4             HttpClient client = new DefaultHttpClient();
     5             HttpGet get = new HttpGet(URI.create(uri));
     6             try {
     7                 HttpResponse response = client.execute(get);
     8                 if (response.getStatusLine().getStatusCode() == 200) {
     9                     BufferedReader reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent(), "UTF-8"));
    10                     StringBuilder builder = new StringBuilder();
    11                     for (String temp = reader.readLine(); temp != null; temp = reader.readLine()) {
    12                         builder.append(temp);
    13                     }
    14                     JSONObject object = new JSONObject(builder.toString().trim());
    15                     String nikeName = object.getString("nickname");
    16                 }
    17             } catch (ClientProtocolException e) {
    18                 // TODO Auto-generated catch block
    19                 e.printStackTrace();
    20             } catch (IOException e) {
    21                 // TODO Auto-generated catch block
    22                 e.printStackTrace();
    23             } catch (JSONException e) {
    24                 // TODO Auto-generated catch block
    25                 e.printStackTrace();
    26             }
    27         }
    28     }
    复制代码

    微信重复登录

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

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

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

    复制代码
     1 private boolean isAccessTokenIsInvalid() {
     2         String url = "https://api.weixin.qq.com/sns/auth?access_token=" + accessToken + "&openid=" + openID;
     3         URI uri = URI.create(url);
     4         HttpClient client = new DefaultHttpClient();
     5         HttpGet get = new HttpGet(uri);
     6         HttpResponse response;
     7         try {
     8             response = client.execute(get);
     9             if (response.getStatusLine().getStatusCode() == 200) {
    10                 HttpEntity entity = response.getEntity();
    11 
    12                 BufferedReader reader = new BufferedReader(new InputStreamReader(entity.getContent(), "UTF-8"));
    13                 StringBuilder sb = new StringBuilder();
    14 
    15                 for (String temp = reader.readLine(); temp != null; temp = reader.readLine()) {
    16                     sb.append(temp);
    17                 }
    18                 JSONObject object = new JSONObject(sb.toString().trim());
    19                 int errorCode = object.getInt("errcode");
    20                 if (errorCode == 0) {
    21                     return true;
    22                 }
    23             }
    24         } catch (ClientProtocolException e) {
    25             // TODO Auto-generated catch block
    26             e.printStackTrace();
    27         } catch (IOException e) {
    28             // TODO Auto-generated catch block
    29             e.printStackTrace();
    30         } catch (JSONException e) {
    31             // TODO Auto-generated catch block
    32             e.printStackTrace();
    33         }
    34         return false;
    35     }
    复制代码

    返回说明

    复制代码
    1 正确的Json返回结果:
    2 { 
    3 "errcode":0,"errmsg":"ok"
    4 }
    5 错误的Json返回示例:
    6 { 
    7 "errcode":40003,"errmsg":"invalid openid"
    8 }
    复制代码

    如果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。

    refresh_token拥有较长的有效期(30天),当refresh_token失效的后,需要用户重新授权。

    复制代码
     1 private void refreshAccessToken() {
     2         String uri = "https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=" + ShareUtil.APP_ID + "&grant_type=refresh_token&refresh_token="
     3                 + refreshToken;
     4         HttpClient client = new DefaultHttpClient();
     5         HttpGet get = new HttpGet(URI.create(uri));
     6         try {
     7             HttpResponse response = client.execute(get);
     8             if (response.getStatusLine().getStatusCode() == 200) {
     9                 BufferedReader reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent(), "UTF-8"));
    10                 StringBuilder builder = new StringBuilder();
    11                 for (String temp = reader.readLine(); temp != null; temp = reader.readLine()) {
    12                     builder.append(temp);
    13                 }
    14                 JSONObject object = new JSONObject(builder.toString().trim());
    15                 accessToken = object.getString("access_token");
    16                 refreshToken = object.getString("refresh_token");
    17                 openID = object.getString("openid");
    18                 expires_in = object.getLong("expires_in");
    19             }
    20         } catch (ClientProtocolException e) {
    21             // TODO Auto-generated catch block
    22             e.printStackTrace();
    23         } catch (IOException e) {
    24             // TODO Auto-generated catch block
    25             e.printStackTrace();
    26         } catch (JSONException e) {
    27             // TODO Auto-generated catch block
    28             e.printStackTrace();
    29         }
    30     }
    复制代码

    返回说明

    复制代码
     1 正确的返回:
     2 { 
     3 "access_token":"ACCESS_TOKEN", 
     4 "expires_in":7200, 
     5 "refresh_token":"REFRESH_TOKEN", 
     6 "openid":"OPENID", 
     7 "scope":"SCOPE" 
     8 }
     9 参数                    说明
    10 access_token       接口调用凭证
    11 expires_in        access_token接口调用凭证超时时间,单位(秒)
    12 refresh_token     用户刷新access_token
    13 openid           授权用户唯一标识
    14 scope          用户授权的作用域,使用逗号(,)分隔
    15 
    16 错误返回样例:
    17 {
    18 "errcode":40030,"errmsg":"invalid refresh_token"
    19 }
    复制代码

    3.服务端获取到新的access_token等信息,并返回给客户端,客户端成功登录或者重新获取授权。

     

  • 相关阅读:
    oracle用户被锁死
    windows远程桌面智能调整大小
    批量ping测试脚本
    信息的组织和提取方法
    BeautifulSoup
    requests模块学习
    Telerik Fiddler 应用方法
    js 时间格式换成 把字符串(yyyymmdd)转换成日期格式(yyyy-mm-dd)记录
    vuedraggable 拖拽 应用 不同列表之间的拖拽
    vue项目图片上传 vant van-uploader 图片上传
  • 原文地址:https://www.cnblogs.com/kenshinobiy/p/8640006.html
Copyright © 2011-2022 走看看