当前位置: 移动技术网 > IT编程>移动开发>Android > 微信第三方登录Android实现代码

微信第三方登录Android实现代码

2019年07月24日  | 移动技术网IT编程  | 我要评论

厦门 租房,本妃卖笑不卖声,刘德华 周星驰

记录一下微信第三方实现登录的方法。还是比较简单。

一、必要的准备工作

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(); 
      } 
    } 
  } 
 
} 

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持移动技术网。

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网