Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> 微信第三方登錄Android實現代碼

微信第三方登錄Android實現代碼

編輯:關於Android編程

記錄一下微信第三方實現登錄的方法。還是比較簡單。

一、必要的准備工作

1.首先需要注冊並被審核通過的微信開放平台帳號,然後創建一個移動應用,也需要被審核;

2.然後到資源中心下載開發微信所需的工具;

下載的網址:點擊打開鏈接,有一個是SDK,一個是簽名生成工具還有一個范例代碼。

3.將SDK文件夾lib下的jar文件libammsdk.jar導入到項目工程中;

4.你的測試手機需要裝好微信客戶端;

5.在項目的AndroidManifest.xml文件中添加如下的權限:

<uses-permission android:name="android.permission.INTERNET"/>  
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> 
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>  
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>  
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>  

6.因為微信登錄後會返回結果到我們自己的應用,因此,我們需要按如下的規則來建立一個可供回調的Activity

a. 在包名(申請移動應用時所填的包名)下新建一個名為wxapi的包,然後再在wxapi的包中新增一個WXEntryActivity類,這個類需要繼承自Activity。

然後再在這個AndroidManifest.xml文件中,將這個activity的export屬性設置為true,如下所示。

 <activity 
      android:name=".wxapi.WXEntryActivity" 
      android:label="@string/title_activity_wxlogin" 
      android:launchMode="singleTop" 
      android:exported="true"> 
      <intent-filter> 
        <action android:name="android.intent.action.MAIN" /> 
        <category android:name="android.intent.category.LAUNCHER" /> 
      </intent-filter> 
</activity> 

b. 實現IWXAPIEventHandler接口,微信發送的請求將回調到onReq方法,發送到微信請求的響應結果將回調到onResp方法

c. 在WXEntryActivity中將接收到的intent及實現了IWXAPIEventHandler接口的對象傳遞給IWXAPI接口的handleIntent方法,如下所示

api.handleIntent(getIntent(), this); 

7.微信認證的時序圖

這裡有一點要注意,就是從上往下數第6個箭頭,即通過code加上appid和appsecret換取access_token,其實這一步是在第三方應用服務器上做的,因為appsecret和access_token直接存儲於客戶端是非常不安全的。Android客戶端獲取code後,把這個code提交給應用服務器,應用服務器上保存有appsecret信息,由應用服務器來獲取access_token,並用access_token來完成其它工作。

二、Android代碼

在上一步添加的WXEntryActivity對應的類文件中添加必要的代碼,我的代碼如下:

package com.example.justyoung.logintest.wxapi; 
 
import android.content.Intent; 
import android.os.Bundle; 
import android.support.v7.app.ActionBarActivity; 
import android.view.View; 
import android.widget.Button; 
import android.widget.Toast; 
 
import com.example.justyoung.logintest.HttpsHelper; 
import com.example.justyoung.logintest.R; 
import com.example.justyoung.logintest.fileExplorer.WXConstant; 
import com.tencent.mm.sdk.modelbase.BaseReq; 
import com.tencent.mm.sdk.modelbase.BaseResp; 
import com.tencent.mm.sdk.modelmsg.SendAuth; 
import com.tencent.mm.sdk.openapi.IWXAPI; 
import com.tencent.mm.sdk.openapi.IWXAPIEventHandler; 
import com.tencent.mm.sdk.openapi.WXAPIFactory; 
 
import java.io.IOException; 
import java.security.KeyManagementException; 
import java.security.NoSuchAlgorithmException; 
import java.util.UUID; 
 
public class WXEntryActivity extends ActionBarActivity implements IWXAPIEventHandler{ 
 
  private Button wxLogin; 
  private IWXAPI api; 
  private static String uuid; 
 
  @Override 
  protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.activity_wxlogin); 
    wxLogin = (Button) findViewById(R.id.wx_login_button); 
    wxLogin.setOnClickListener(new WXLoginEvent()); 
    api = WXAPIFactory.createWXAPI(this, WXConstant.APPID); 
    api.registerApp(WXConstant.APPID); 
    api.handleIntent(getIntent(), this); 
  } 
 
  @Override 
  public void onReq(BaseReq baseReq) { 
 
 
  } 
 
  @Override 
  public void onNewIntent(Intent intent) { 
    super.onNewIntent(intent); 
    setIntent(intent); 
    api.handleIntent(intent, this); 
  } 
 
  @Override 
  public void onResp(BaseResp resp) { 
    String result; 
    switch (resp.errCode) { 
      case BaseResp.ErrCode.ERR_OK: 
        result = "OK"; 
        SendAuth.Resp regResp = (SendAuth.Resp)resp; 
        if (!regResp.state.equals(uuid)) 
          return; 
        String code = regResp.code; 
        new WXLoginThread("https://192.168.2.133:8443/CloudStorageServer/wechat/login?code=" + code).start(); 
        break; 
      case BaseResp.ErrCode.ERR_USER_CANCEL: 
        result = "USER_CANCEL"; 
        break; 
      case BaseResp.ErrCode.ERR_AUTH_DENIED: 
        result = "ERR_AUTH_DENIED"; 
        break; 
      default: 
        result = "errcode_unknown"; 
        break; 
    } 
 
    Toast.makeText(this, result, Toast.LENGTH_LONG).show(); 
 
  } 
 
  class WXLoginEvent implements View.OnClickListener { 
    @Override 
    public void onClick(View v) { 
      uuid = UUID.randomUUID().toString(); 
      final SendAuth.Req req = new SendAuth.Req(); 
      req.scope = "snsapi_userinfo"; 
      req.state = uuid; 
      api.sendReq(req); 
    } 
  } 
 
  private class WXLoginThread extends Thread { 
    private String url; 
 
    public WXLoginThread(String url) { 
      this.url = url; 
    } 
 
    @Override 
    public void run() { 
      HttpsHelper httpsHelper = new HttpsHelper(); 
      try { 
        httpsHelper.prepareHttpsConnection(url); 
        String response = httpsHelper.connect(); 
      } catch (KeyManagementException e) { 
        e.printStackTrace(); 
      } catch (NoSuchAlgorithmException e) { 
        e.printStackTrace(); 
      } catch (IOException e) { 
        e.printStackTrace(); 
      } 
    } 
  } 
} 

代碼中的如下片段是用來拉起微信認證界面的。這裡我使用了uuid來作為state參數,(該參數可用於防止csrf攻擊(跨站請求偽造攻擊),建議第三方帶上該參數,可設置為簡單的隨機數加session進行校驗)。

uuid = UUID.randomUUID().toString(); 
final SendAuth.Req req = new SendAuth.Req(); 
req.scope = "snsapi_userinfo"; 
req.state = uuid; 
api.sendReq(req); 

在用戶接受認證後,微信應用會回調IWXAPIEventHandler接口的onResp方法。在該方法中,首先判斷返回的resp的狀態,若是正常狀態,則判斷state,然後從再從resp中獲取code值。至此客戶端便完成了它的工作。

因為客戶端保留appsecret和access_token是非常不安全的,因此剩余信息的獲取應放到我們的應用服務器上進行。

三、應用服務器代碼

在Anroid客戶端獲取到code後,可提交到我們自己的應用服務器,在我們的應用服務器再通過code,來獲取access_token,openid等用戶信息。

1.通過code獲取access_token,openid的方法是使用GET請求,按以下方式請求微信接口:

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

2.通過access_token獲取用戶的一些信息的方式是通過GET請求使用微信的接口:

https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID

下面貼一下我自己使用的代碼:

private void handle(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 
    String code = getParameter(request, "code"); 
    if (isArgumentNullOrEmpty(code)) { 
      Log.logger.info("code為空"); 
      return; 
    } 
    Log.logger.info("收到code: " + code); 
    try { 
      AccessToken accessToken = new AccessToken("/sns/oauth2/access_token", "authorization_code", code); 
      AccessToken.UserData userData = accessToken.getMetaData().getUserInfo(); 
      ... // userData中就是我們通過access_token獲取的用戶信息了。 
    } catch (WeiXinException e) { 
      Log.logException(e); 
      writeMessage(response, e.getMessage()); 
      return; 
    } catch (Exception e) { 
      Log.logException(e); 
      writeMessage(response, "login error"); 
      return; 
    } 
  } 
package com.cyber_space.thirdparty.weixin; 
 
import java.io.IOException; 
import java.lang.reflect.Field; 
import java.net.URI; 
import java.net.URISyntaxException; 
 
import org.apache.http.HttpEntity; 
import org.apache.http.client.ClientProtocolException; 
import org.apache.http.client.methods.CloseableHttpResponse; 
import org.apache.http.client.methods.HttpGet; 
import org.apache.http.client.utils.URIBuilder; 
import org.apache.http.entity.BufferedHttpEntity; 
import org.apache.http.impl.client.CloseableHttpClient; 
import org.apache.http.impl.client.HttpClients; 
import org.apache.http.util.EntityUtils; 
 
import com.cyber_space.util.JsonUtil; 
 
public class AccessToken { 
 
  CloseableHttpClient httpClient; 
  HttpGet httpGet; 
  URI uri; 
  String code; 
 
  /** 
   * 用於公眾號 
   * 
   * @throws URISyntaxException 
   */ 
  public AccessToken() throws URISyntaxException { 
 
    uri = new URIBuilder().setScheme("https").setHost("api.weixin.qq.com").setPath("/cgi-bin/token") 
        .setParameter("grant_type", "client_credential").setParameter("appid", WeiXinConfig.APP_ID) 
        .setParameter("secret", WeiXinConfig.APP_SECRET).build(); 
    httpClient = HttpClients.createDefault(); 
    httpGet = new HttpGet(uri); 
  } 
 
  public AccessToken(String path, String grantType, String code) throws URISyntaxException { 
    uri = new URIBuilder().setScheme("https").setHost("api.weixin.qq.com").setPath(path) 
        .setParameter("grant_type", grantType).setParameter("appid", WeiXinConfig.APP_ID) 
        .setParameter("secret", WeiXinConfig.APP_SECRET).setParameter("code", code).build(); 
    httpClient = HttpClients.createDefault(); 
    httpGet = new HttpGet(uri); 
  } 
 
  public String getAccessToken() throws ClientProtocolException, IOException { 
    CloseableHttpResponse response = null; 
    try { 
      response = httpClient.execute(httpGet); 
      HttpEntity httpEntity = response.getEntity(); 
      if (httpEntity == null) 
        return null; 
      httpEntity = new BufferedHttpEntity(httpEntity); 
      String returnString = EntityUtils.toString(httpEntity); 
      String accessToken = com.cyber_space.util.JsonUtil.getAttribute(returnString, "access_token"); 
      return accessToken; 
    } finally { 
      response.close(); 
    } 
  } 
 
  /** 
   * 獲得用戶的元數據信息,只包括openid和access_token 
   * 
   * @return 
   * @throws ClientProtocolException 
   * @throws IOException 
   * @throws WeiXinException 
   */ 
  public UserData getMetaData() throws ClientProtocolException, IOException, WeiXinException { 
    CloseableHttpResponse response = null; 
    try { 
      response = httpClient.execute(httpGet); 
      HttpEntity httpEntity = response.getEntity(); 
      if (httpEntity == null) 
        return null; 
      httpEntity = new BufferedHttpEntity(httpEntity); 
      String returnString = EntityUtils.toString(httpEntity); 
      JsonUtil jUtil = new JsonUtil(returnString, JsonUtil.JSONOBJECT); 
      String error = null; 
      try { 
        error = jUtil.getAttribute("errcode"); 
      } catch (Exception e) { 
      } 
      if (error != null && !error.equals("")) { 
        throw new WeiXinException(WeiXinException.INVALID_OPENID); 
      } 
      String openid = jUtil.getAttribute("openid"); 
      String accessToken = jUtil.getAttribute("access_token"); 
      UserData uData = new UserData(openid, accessToken); 
      return uData; 
    } finally { 
      response.close(); 
    } 
  } 
 
  public class UserData { 
    public String openid; 
    public String accessToken; 
    public String nickname; 
    public String sex; 
    public String province; 
    public String city; 
    public String country; 
    public String headimgurl; 
    public String privilege; 
    public String unionid; 
 
    public UserData(String openid, String accessToken) { 
      this.openid = openid; 
      this.accessToken = accessToken; 
    } 
 
    public UserData getUserInfo() 
        throws IOException, IllegalArgumentException, IllegalAccessException, URISyntaxException, WeiXinException { 
      URI uri = new URIBuilder().setScheme("https").setHost("api.weixin.qq.com").setPath("/sns/userinfo") 
          .setParameter("access_token", this.accessToken).setParameter("openid", this.openid).build(); 
      HttpGet httpGet = new HttpGet(uri); 
      CloseableHttpResponse response = null; 
      try { 
        response = httpClient.execute(httpGet); 
        HttpEntity httpEntity = response.getEntity(); 
        if (httpEntity == null) 
          throw null; 
        httpEntity = new BufferedHttpEntity(httpEntity); 
        String jsonString = EntityUtils.toString(httpEntity); 
        JsonUtil jUtil = new JsonUtil(jsonString, JsonUtil.JSONOBJECT); 
        String errcode = null; 
        try { 
          errcode = jUtil.getAttribute("errcode"); 
        } catch (Exception e) { 
        } 
        // 通過反射循環賦值 
        if (errcode == null || errcode.equals("")) { 
          for (Field i : getClass().getFields()) { 
            if (!i.getName().equals("accessToken")) 
              i.set(this, jUtil.getAttribute(i.getName())); 
          } 
          return this; 
        } 
        else { 
          throw new WeiXinException(WeiXinException.INVALID_ACCESSTOKEN); 
        } 
      } finally { 
        response.close(); 
      } 
    } 
  } 
 
} 

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持本站。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved