• 详解如何进行第三方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等信息,并返回给客户端,客户端成功登录或者重新获取授权。

     

  • 相关阅读:
    How to create jar for Android Library Project
    Very large tabs in eclipse panes on Ubuntu
    64bit Ubuntu, Android AAPT, R.java
    Linux(Ubuntu)下如何安装JDK
    Configure xterm Fonts and Colors for Your Eyeball
    建立、配置和使用Activity——启动其他Activity并返回结果
    建立、配置和使用Activity——使用Bundle在Activity之间交换数据
    建立、配置和使用Activity——启动、关闭Activity
    建立、配置和使用Activity——Activity
    异步任务(AsyncTask)
  • 原文地址:https://www.cnblogs.com/kenshinobiy/p/8640006.html
Copyright © 2020-2023  润新知