微信移動應用接入開發, Android 授權微信登入獲取openid,unionid等,score引數錯誤或者沒有scope許可權
寫這篇文章的原因,就是自己氣不過。專案需求突然要做微信公眾號與App微信分享使用同個使用者體系,接到任務是確認這使用者體系,於是需要確認android app端獲取授權使用者後返回的unionid與微信公眾號授權使用者返回的unionid是否一致。但是,為了獲取這個unionid,讓我捉急了一個下午,因此,寫這篇文章可以為後來的朋友帶來方便。
第一步:請求CODE:
app介面可以設定一個button,在button的onClick()中填寫以下程式碼:
<pre class="java" name="code">final SendAuth.Req req = new SendAuth.Req(); req.scope = "snsapi_userinfo"; req.state = "wxdemo"; api.sendReq(req);
其中:
scope代表你應用的許可權,下圖展示某個應用的許可權:
snsapi_base屬於基礎介面,若應用已擁有其它scope許可權,則預設擁有snsapi_base的許可權。使用snsapi_base可以讓移動端網頁授權繞過跳轉授權登入頁請求使用者授權的動作,直接跳轉第三方網頁帶上授權臨時票據(code),但會使得使用者已授權作用域(scope)僅為snsapi_base,從而導致無法獲取到需要使用者授權才允許獲得的資料和基礎功能。 snsapi_userinfo:這個屬性許可權比snsapi_base高,使用此屬性,可以讓移動端網頁授權跳轉授權登入頁請求(本篇文章就是採用這個屬性,所以下面可以看到示例的跳往京東授權登入頁請求)
倘若微訊號還沒申請微信登入功能,那麼將出現錯誤頁面:
若正確:
第二步 獲取code
微信的回撥都是在WXEntryActivity中的public void onResp(BaseResp resp)函式中得到的,也就是說,我們的code可以在resp中獲取到。
按照微信官方文件:
點選第一步事例中京東商城“確認登入”按鈕按道理說是可以從SendAuth的Resp獲取到code欄位的:
例如:
<span style="font-size:18px;">case BaseResp.ErrCode.ERR_OK: String code = ((SendAuth.Resp) resp).code; Break</span>
但是這時,你會發現找不到code這個屬性。也就是說,按照官網說的去獲取是獲取不到code的。那該怎麼獲取呢?下面給你講解超級坑爹的方法;
case BaseResp.ErrCode.ERR_OK:
result = R.string.errcode_success;
String code = ((SendAuth.Resp) resp).token;
break;
沒錯,你沒看錯,真正的code放在了屬性為”token”欄位中;
第三步 獲取登入授權後的資訊,包含openid、unionid等
根據微信官網提到,這個步驟叫通過code獲取access_token,需要用get方式請求
(你的Appid)&secret=(你的app secret)&code=(第二步中獲取到的code)&grant_type=authorization_code,其中appid 和 app secret就是你在微信開放平臺申請移動應用後,在應用介面可以找到。
上面的連結是https連結,Android app要訪問https需要構造一個新的HttpClient,
以下附上第三步所需用到的程式碼:
// 第三方應用傳送到微信的請求處理後的響應結果,會回撥到該方法
@Override
public void onResp(BaseResp resp) {
int result = 0;
switch (resp.errCode) {
case BaseResp.ErrCode.ERR_OK:
result = R.string.errcode_success;
String code = ((SendAuth.Resp) resp).token;
String url = "https://api.weixin.qq.com/sns/oauth2/access_token" +
"?appid=" + Constants.APP_ID +
"&secret=" +Constants.APP_SECRET +
"&code=" + code +
"&grant_type=authorization_code";
String result1 = new String(httpGet(url));
Log.d("WXEntryActivity", result1);
break;
case BaseResp.ErrCode.ERR_USER_CANCEL:
result = R.string.errcode_cancel;
break;
case BaseResp.ErrCode.ERR_AUTH_DENIED:
result = R.string.errcode_deny;
break;
default:
result = R.string.errcode_unknown;
break;
}
Toast.makeText(this, result, Toast.LENGTH_LONG).show();
}
public static byte[] httpGet(final String url) {
if (url == null || url.length() == 0) {
return null;
}
HttpClient httpClient = getNewHttpClient();
HttpGet httpGet = new HttpGet(url);
try {
HttpResponse resp = httpClient.execute(httpGet);
if (resp.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
return null;
}
return EntityUtils.toByteArray(resp.getEntity());
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
private static HttpClient getNewHttpClient() {
try {
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
trustStore.load(null, null);
SSLSocketFactory sf = new SSLSocketFactoryEx(trustStore);
sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
HttpParams params = new BasicHttpParams();
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);
SchemeRegistry registry = new SchemeRegistry();
registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
registry.register(new Scheme("https", sf, 443));
ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry);
return new DefaultHttpClient(ccm, params);
} catch (Exception e) {
return new DefaultHttpClient();
}
}
private static class SSLSocketFactoryEx extends SSLSocketFactory {
SSLContext sslContext = SSLContext.getInstance("TLS");
public SSLSocketFactoryEx(KeyStore truststore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
super(truststore);
TrustManager tm = new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
return null;
}
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) throws java.security.cert.CertificateException {
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) throws java.security.cert.CertificateException {
}
};
sslContext.init(null, new TrustManager[] { tm }, null);
}
@Override
public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException, UnknownHostException {
return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose);
}
@Override
public Socket createSocket() throws IOException {
return sslContext.getSocketFactory().createSocket();
}
}