登录 立即注册
安币:

查看: 491|回复: 6

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

[复制链接]

308

主题

834

帖子

705

安币

手工艺人

发表于 2017-12-25 11:35:37 | 显示全部楼层 |阅读模式

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

        一、必要的准备工作

        1.首先需要注册并被审核通过的微信开放平台帐号,然后创建一个移动应用,也需要被审核;

        2.然后到资源中心下载开发微信所需的工具;

        下载的网址:点击打开链接,有一个是sdk,一个是签名生成工具还有一个范例代码。

        3.将sdk文件夹lib下的jar文件libammsdk.jar导入到项目工程中;

        4.你的测试手机需要装好微信客户端;

        5.在项目的androidmanifest.xml文件中添加如下的权限:

[Java] 查看源文件 复制代码
<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,如下所示。

[Java] 查看源文件 复制代码
 <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方法,如下所示

[Java] 查看源文件 复制代码
api.handleintent(getintent(), this); 

        7.微信认证的时序图

        这里有一点要注意,就是从上往下数第6个箭头,即通过code加上appid和appsecret换取access_token,其实这一步是在第三方应用服务器上做的,因为appsecret和access_token直接存储于客户端是非常不安全的。android客户端获取code后,把这个code提交给应用服务器,应用服务器上保存有appsecret信息,由应用服务器来获取access_token,并用access_token来完成其它工作。


        二、android代码

        在上一步添加的wxentryactivity对应的类文件中添加必要的代码,我的代码如下:

[Java] 查看源文件 复制代码
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

        代码中的如下片段是用来拉起微信认证界面的。这里我使用了uuid来作为state参数,(该参数可用于防止csrf攻击(跨站请求伪造攻击),建议第三方带上该参数,可设置为简单的随机数加session进行校验)。

[Java] 查看源文件 复制代码
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

[Java] 查看源文件 复制代码
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; 
    } 
  } 



[Java] 查看源文件 复制代码
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(); 
      } 
    } 
  } 
 
} 


2

主题

9311

帖子

2493

安币

Android大神

Rank: 6Rank: 6

发表于 2017-12-25 21:29:05 | 显示全部楼层
感谢大神~

0

主题

9221

帖子

2900

安币

Android大神

Rank: 6Rank: 6

发表于 2017-12-26 11:28:19 | 显示全部楼层
楼主是好人,回个帖会有安币吗?

1

主题

9104

帖子

2924

安币

Android大神

Rank: 6Rank: 6

发表于 2017-12-27 02:44:48 | 显示全部楼层
安卓巴士是个不错的网站,我来顶个贴~

7

主题

9465

帖子

1981

安币

Android大神

Rank: 6Rank: 6

发表于 2017-12-27 23:03:13 | 显示全部楼层
安卓巴士是个不错的网站,我来顶个贴~

8

主题

9169

帖子

3560

安币

码皇(巴士元老)

Rank: 8Rank: 8

发表于 2017-12-29 09:18:42 | 显示全部楼层
每次我都积极回帖的,想要安币~

0

主题

4

帖子

31

安币

初级码农

Rank: 1

发表于 2019-1-6 01:05:13 | 显示全部楼层
很给力,安卓巴士有你更精彩!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

站长推荐

通过邮件订阅最新安卓weekly信息
上一条 /4 下一条

下载安卓巴士客户端

全国最大的安卓开发者社区
联系我们
关闭
合作电话:
15618560077
Email:
805941275@qq.com
商务市场合作/投稿
问题反馈及帮助
联系我们

广告投放| 下载客户端|申请友链|手机版|站点统计|安卓巴士 ( 粤ICP备15117877号 )

快速回复 返回顶部 返回列表