乐码库:一个极速、放心、纯净的下载站! 更新: 资源发布
  • 您的位置:首页 > 技术文档 > AndRoid > 微信第三方登录Android实现代码
  • 收藏本页
      微信第三方登录Android实现代码
      发布时间:2016-12-21 08:07:03 关键词: android,第三方登录,android,接入微信登录,android第三方登录sdk
      内容简介:本篇文章主要介绍了微信第三方登录Android实现代码,可以通过微信登陆到第三方应用,有需要的可以了解一下。<br />

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

    一、必要的准备工作

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

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

    下载的网址:<a target="_blank" href="https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419319167&token=def4cb25e8948b097c4adcf443fffa1c8eefc57f&lang=zh_CN">点击打开链接,有一个是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请求,按以下方式请求微信接口:

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

    2.通过access_token获取用户的一些信息的方式是通过GET请求使用微信的接口:

    <a href="https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID">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(); 
          } 
        } 
      } 
     
    } 

    以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持乐码库。

      最新更新
      热门排行榜