微信登陆遵循协议Aouth2.0中的受权码模式api
咱们来看一下Aouth2.0中的受权码模式是怎么定义的:服务器
受权码模式(authorization code)是功能最完整、流程最严密的受权模式。它的特色就是经过客户端的后台服务器,与”服务提供商”的认证服务器进行互动。
它的步骤以下:微信
(A)用户访问客户端,后者将前者导向认证服务器。app
(B)用户选择是否给予客户端受权。ide
(C)假设用户给予受权,认证服务器将用户导向客户端事先指定的”重定向URI”(redirection URI),同时附上一个受权码。ui
(D)客户端收到受权码,附上早先的”重定向URI”,向认证服务器申请令牌。这一步是在客户端的后台的服务器上完成的,对用户不可见。this
(E)认证服务器核对了受权码和重定向URI,确认无误后,向客户端发送访问令牌(access token)和更新令牌(refresh token)url
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,可拉起微信并打开受权登陆页(前提是你安装了微信应用并已登陆,未登陆的会引导你先登陆),以下图:spa
1.若是微信受权页不显示,请检查你的APP签名是否和你在腾讯开放平台的APP签名一致,不一致可修改腾讯开放平台中的APP签名,修改后重装微信或清除微信数据后重试。3d
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:
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后,进行接口调用,有如下前提:
对于接口做用域(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等信息,并返回给客户端,客户端成功登陆或者从新获取受权。