談?wù)劦谌紸pp接入微信登錄 解讀
接入微信登錄:
1、準(zhǔn)備工作
1.在微信開(kāi)放平臺(tái)https://open.weixin.qq.com/注冊(cè)成為開(kāi)發(fā)者。
2.在“管理中心”中創(chuàng)建一個(gè)移動(dòng)應(yīng)用,需“應(yīng)用名稱、簡(jiǎn)介、及28*28和108*108的PNG圖片各一張,且大小不超過(guò)300k”,點(diǎn)擊下一步,需“應(yīng)用官網(wǎng)地址,應(yīng)用簽名及包名”等信息,然后即可提交審核。
說(shuō)明:
應(yīng)用簽名:可在微信開(kāi)發(fā)平臺(tái)的資源中心》》資源下載》》中下載“簽名生成工具”,用戶獲取已經(jīng)安裝到手機(jī)的第三方應(yīng)用的簽名。輸入應(yīng)用包名,即可獲得該應(yīng)用的簽名值。
3.提交審核后,在7個(gè)工作日內(nèi)騰訊將給出審核結(jié)果。(通常較快,幾個(gè)小時(shí)就可反饋結(jié)果)
2、微信登錄接入
微信登錄遵循協(xié)議Aouth2.0中的授權(quán)碼模式,先介紹一下Aouth2.0的流程:
3、微信登錄的官方文檔將微信登錄分為3個(gè)步驟:
第一步.請(qǐng)求code:
{ // send oauth request Final SendAuth.Req req = new SendAuth.Req(); req.scope = "snsapi_userinfo"; req.state = "wechat_sdk_demo_test"; api.sendReq(req); }
用這段代碼向微信開(kāi)放平臺(tái)請(qǐng)求授權(quán)碼code,可拉起微信并打開(kāi)授權(quán)登錄頁(yè)(前提是你安裝了微信應(yīng)用并已登錄,未登錄的會(huì)引導(dǎo)你先登錄)下圖:
需要注意的情況:
1.如果微信授權(quán)頁(yè)不顯示,請(qǐng)檢查你的APP簽名是否和你在騰訊開(kāi)放平臺(tái)的APP簽名一致,不一致可修改騰訊開(kāi)放平臺(tái)中的APP簽名,修改后重裝微信或清除微信數(shù)據(jù)后重試。
2.在你的包名相應(yīng)目錄下新建一個(gè)wxapi目錄,并在該wxapi目錄下新增一個(gè)WXEntryActivity類,該類繼承自Activity(例如應(yīng)用程序的包名為net.sourceforge,則新的包名為:net.sourceforge.wxapi),此處應(yīng)注意包名不要弄錯(cuò),新增類的名字必須為WXEntryActivity。
返回說(shuō)明
用戶點(diǎn)擊授權(quán)后,微信客戶端會(huì)被拉起,跳轉(zhuǎn)至授權(quán)界面,用戶在該界面點(diǎn)擊允許或取消,SDK通過(guò)SendAuth的Resp返回?cái)?shù)據(jù)給調(diào)用方?;卣{(diào)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); }
客戶端收到授權(quán)碼后,向自己的服務(wù)器發(fā)起登錄請(qǐng)求,并附帶收到的授權(quán)碼。
服務(wù)端收到登錄請(qǐng)求,向微信開(kāi)放平臺(tái)請(qǐng)求獲取access_token,微信開(kāi)放平臺(tái)返回Json字符串:
第二步:通過(guò)code獲取access_token:
獲取第一步的code后,請(qǐng)求以下鏈接獲取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; }
參數(shù)說(shuō)明
參數(shù) 是否必須 說(shuō)明
appid 是 應(yīng)用唯一標(biāo)識(shí),在微信開(kāi)放平臺(tái)提交應(yīng)用審核通過(guò)后獲得
secret 是 應(yīng)用密鑰AppSecret,在微信開(kāi)放平臺(tái)提交應(yīng)用審核通過(guò)后獲得
code 是 填寫(xiě)第一步獲取的code參數(shù)
grant_type 是 填authorization_code回說(shuō)明**
正確的返回:
{ "access_token":"ACCESS_TOKEN", "expires_in":7200, "refresh_token":"REFRESH_TOKEN", "openid":"OPENID", "scope":"SCOPE", "unionid":"o6_bmasdasdsad6_2sgVt7hMZOPfL" }
參數(shù) 說(shuō)明
access_token 接口調(diào)用憑證
expires_in access_token 接口調(diào)用憑證超時(shí)時(shí)間,單位(秒)
refresh_token 用戶刷新access_token
openid 授權(quán)用戶唯一標(biāo)識(shí)
scope 用戶授權(quán)的作用域,使用逗號(hào)(,)分隔
unionid 只有在用戶將公眾號(hào)綁定到微信開(kāi)放平臺(tái)帳號(hào)后,才會(huì)出現(xiàn)該字段。
錯(cuò)誤返回樣例:
{"errcode":40029,"errmsg":"invalid code"}
第三步:通過(guò)access_token調(diào)用接口
獲取access_token后,進(jìn)行接口調(diào)用,有以下前提:
- access_token有效且未超時(shí);
- 微信用戶已授權(quán)給第三方應(yīng)用帳號(hào)相應(yīng)接口作用域(scope)。
對(duì)于接口作用域(scope),能調(diào)用的接口有以下:
授權(quán)作用域(scope) 接口 接口說(shuō)明
snsapi_base /sns/oauth2/access_token 通過(guò)code換取 access_token、refresh_token和已授權(quán)scope
/sns/oauth2/refresh_token 刷新或續(xù)期access_token使用
/sns/auth 檢查access_token有效性
snsapi_userinfo /sns/userinfo 獲取用戶個(gè)人信息
其中snsapi_base屬于基礎(chǔ)接口,若應(yīng)用已擁有其它scope權(quán)限,則默認(rèn)擁有snsapi_base的權(quán)限。使用snsapi_base可以讓移動(dòng)端網(wǎng)頁(yè)授權(quán)繞過(guò)跳轉(zhuǎn)授權(quán)登錄頁(yè)請(qǐng)求用戶授權(quán)的動(dòng)作,直接跳轉(zhuǎn)第三方網(wǎng)頁(yè)帶上授權(quán)臨時(shí)票據(jù)(code),但會(huì)使得用戶已授權(quán)作用域(scope)僅為snsapi_base,從而導(dǎo)致無(wú)法獲取到需要用戶授權(quán)才允許獲得的數(shù)據(jù)和基礎(chǔ)功能。
以獲取用戶信息為例:
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(); } } }
微信重復(fù)登錄
假設(shè)用戶已經(jīng)獲得授權(quán),則下次登錄時(shí)只需要驗(yàn)證access_token是否有效,無(wú)效則重新獲取授權(quán),有效則無(wú)需重新獲得授權(quán)。
1.用戶向自己的服務(wù)器請(qǐng)求登錄,登錄方式為微信登錄,附帶上次登錄返回的的access_token
2.服務(wù)器收到用戶的登錄請(qǐng)求,向微信開(kāi)放平臺(tái)發(fā)送access_token是否有效的驗(yàn)證請(qǐng)求如下:
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; }
返回說(shuō)明
正確的Json返回結(jié)果:
{ "errcode":0,"errmsg":"ok" }
錯(cuò)誤的Json返回示例:
{ "errcode":40003,"errmsg":"invalid openid" }
如果access_token有效,服務(wù)端將信息返回給客戶端,客戶端成功登錄。
如果access_token無(wú)效,服務(wù)端向微信開(kāi)放平臺(tái)發(fā)送刷新access_token的請(qǐng)求如下:
access_token是調(diào)用授權(quán)關(guān)系接口的調(diào)用憑證,由于access_token有效期(目前為2個(gè)小時(shí))較短,當(dāng)access_token超時(shí)后,可以使用refresh_token進(jìn)行刷新,access_token刷新結(jié)果有兩種:
1.若access_token已超時(shí),那么進(jìn)行refresh_token會(huì)獲取一個(gè)新的access_token,新的超時(shí)時(shí)間;
2.若access_token未超時(shí),那么進(jìn)行refresh_token不會(huì)改變access_token,但超時(shí)時(shí)間會(huì)刷新,相當(dāng)于續(xù)期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" }
參數(shù) 說(shuō)明
access_token 接口調(diào)用憑證
expires_in access_token接口調(diào)用憑證超時(shí)時(shí)間,單位(秒)
refresh_token 用戶刷新access_token
openid 授權(quán)用戶唯一標(biāo)識(shí)
scope 用戶授權(quán)的作用域,使用逗號(hào)(,)分隔
錯(cuò)誤返回樣例:
{ "errcode":40030,"errmsg":"invalid refresh_token" }
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
JavaScript的9個(gè)陷阱及評(píng)點(diǎn)分析
以下是JavaScript容易犯錯(cuò)的九個(gè)陷阱。雖然不是什么很高深的技術(shù)問(wèn)題,但注意一下,會(huì)使您的編程輕松些,即所謂make life easier. 筆者對(duì)某些陷阱會(huì)混雜一些評(píng)點(diǎn)。2008-05-05jquery 滾動(dòng)條事件簡(jiǎn)單實(shí)例
這篇文章介紹了jquery滾動(dòng)條事件的簡(jiǎn)單實(shí)例,有需要的朋友可以參考一下2013-07-07JavaScript實(shí)現(xiàn)存儲(chǔ)HTML字符串示例
這篇文章主要介紹了JavaScript存儲(chǔ)HTML字符串的具體實(shí)現(xiàn),需要的朋友可以參考下2014-04-04淺談bootstrap源碼分析之tab(選項(xiàng)卡)
下面小編就為大家?guī)?lái)一篇淺談bootstrap源碼分析之tab(選項(xiàng)卡)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-06-06實(shí)現(xiàn)web打印的各種方法介紹及實(shí)現(xiàn)代碼
web的打印方法具我自己懂得知道的有:JQuery插件Jqprint實(shí)現(xiàn);JQery打印插件PrintArea實(shí)現(xiàn)網(wǎng)頁(yè)打印;CSS控制網(wǎng)頁(yè)打印樣式,本文詳細(xì)介紹實(shí)現(xiàn)步驟,感興趣的朋友可以了解下2013-01-01