微信第三方登录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请求,按以下方式请求微信接口:
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(); } } } }
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。