人人网的OAuth认证Android下的实现(非SDK方式)

前段时间准备做一个可以一键发布微博(状态)到人人网、QQ空间及各大微博的应用,新浪微博和腾讯微博的网上资料比较多,OAuth的认证方式也差不多,很容易就搞定了。只是人人网的搞得很另类,费了很大的周折才算完成,不过让人郁闷的是发布人人网状态的API属于“高级API”,要通过审核才能使用,而悲剧是我的应用最终没有通过审核,而未通过的审核的原因也把我雷到外焦里嫩,不发牢骚了。因为没有通过审核,这个应用也只好作罢,因为主要是为了能够同步人人网的(同步各大微博的应用早就存在了,我就不跟风了),虽然应用没有最终发布,但人人网的这套认证方式还是摸清了,今天整理了一下贴出来,希望对后来者有用。

之前也做过一个跟人人网相关的应用——生日提醒,同步人人网的好友信息,但是是通过人人网的Android SDK方式来实现的,这样比较省事,但是一个弊端就是需要引入人人网SDK,开发出来的应用体积会变大,尤其是我要开发同步各个平台的应用,如果都引入各自的SDK,体积会大到令人发指,所以选择了采用直接调用API的方式。下面是具体步骤:

一、注册人人网应用,获取API Key和Secret Key

这个就不用多说了,申请开发应用后就会获得。

二、获取accessToken

在之前,调用人人网API时必须提供api_key和session_key,而OAuth2.0验证授权后,使用获得的accessToken就可以了,比较省事,因此毫不犹豫采用这种方式。

和别的开放平台OAuth认证的一样,应用需要跳转到官方的一个认证页面,用户输入正确的信息确认授权后再返回应用,然后才能调用具体的API,OAuth认证的优点就不说了啊。认证我最初采用的方式是传入认证的URL,然后调用系统浏览器,用户确认后获取浏览器返回的信息。这种方式在Android自带的浏览器下没有问题,但是在如UC等一些第三方浏览器上,认证后并不会从浏览器返回应用,所以这种方式是不行的。我的解决方法是通过在本应用嵌入一个WebView,认证操作都放在这个WebView中,这样我们就可以自由操作并获取我们想要的数据了。

人人网OAuth2.0授权页面url是“https://graph.renren.com/oauth/authorize”,并带上参数“client_id”、“redirect_uri”、“response_type”。下面对着几个参数进行说明:

  • client_id:就是在第一步中申请的API Key;
  • redirect_uri:授权成功后跳转到的页面url,由于客户端类应用,没有自己的Web Server,在使用OAuth2.0 User-Agent Flow进行授权时,可以将redirect_uri指定为人人网提供的授权成功页面“http://graph.renren.com/oauth/login_success.html”就可以了;
  • response_type:返回的类型,我们需要的是accessToken,所以设置成token;
  • scope:需要请求的权限,多个权限以空格分隔,这里我们需要更新状态的status_update和发布照片的photo_upload权限。 

     

    不多说,下面上代码,是一个简单的Activity,里面只有一个WebView控件,在WebView中进行所有操作,获取accessToken保存在中:

    1. /** 
    2.  * 人人网授权页面 
    3.  * @author iStar 
    4.  * 
    5.  */  
    6. public class RenrenAuthActivity extends Activity {  
    7.     private WebView webView;  
    8.     private String accessToken = null;  
    9.     private SharedData share;  
    10.     String authUrl = "https://graph.renren.com/oauth/authorize?client_id="  
    11.         + GlobalData.RENREN_KEY+"&response_type=token"  
    12.         + "&redirect_uri=http://graph.renren.com/oauth/login_success.html&display=mobile"  
    13.         + "&scope=status_update photo_upload";  
    14.   
    15.     @Override  
    16.     protected void onCreate(Bundle savedInstanceState) {  
    17.         super.onCreate(savedInstanceState);  
    18.         setContentView(R.layout.activity_oauth);  
    19.         share = new SharedData(this);  
    20.         webView = (WebView) findViewById(R.id.web);  
    21.   
    22.         bindViews();  
    23.     }  
    24.   
    25.     private void bindViews() {  
    26.         WebSettings settings = webView.getSettings();  
    27.         settings.setJavaScriptEnabled(true);  
    28.         settings.setSupportZoom(true);  
    29.         settings.setBuiltInZoomControls(true);  
    30.         webView.loadUrl(authUrl);  
    31.         webView.requestFocusFromTouch();  
    32.   
    33.         WebViewClient wvc = new WebViewClient() {  
    34.             @Override  
    35.             public void onPageFinished(WebView view, String url) {  
    36.                 super.onPageFinished(view, url);  
    37.                 //人人网用户名和密码验证通过后,刷新页面时即可返回accessToken  
    38.                 String reUrl = webView.getUrl();  
    39.                 Log.d(GlobalData.TAG, "reUrl:" + reUrl);  
    40.                 if (reUrl.indexOf("access_token") != -1) {  
    41.                     //截取url中的accessToken  
    42.                     int startPos = reUrl.indexOf("token=") + 6;  
    43.                     int endPos = reUrl.indexOf("&expires_in");  
    44.                     accessToken = reUrl.substring(startPos, endPos);  
    45.                     //保存获取到的accessToken  
    46.                     share.saveRenrenToken(accessToken);  
    47.                     Log.d(GlobalData.TAG, "accessToken:" + accessToken);  
    48.                     Toast.makeText(RenrenAuthActivity.this"验证成功", Toast.LENGTH_SHORT).show();  
    49.                     finish();  
    50.                 }  
    51.             }  
    52.         };  
    53.         webView.setWebViewClient(wvc);  
    54.     }  
    55.   
    56. }  
    三、通过出示AccessToken调用API

    我要实现的功能是调用人人网的API更新用户状态,对应的API是status.set,参数表如下:

    2011-08-14_17-09-32

    上图有详细的说明这里要说的是sig这个参数,为了确保应用与人人API服务器之间的安全通信,防止Secret Key盗用,数据篡改等恶意攻击,人人API 服务器使用了签名机制(即sig参数)来认证应用。签名是由请求参数和应用的私钥Secret Key经过MD5加密后生成的字符串。应用在调用人人API之前,要计算出签名,并追加到请求参数中。具体生产步骤如下:

    假设某个人人API需要3个参数,分别是“k1”、“k2”、“k3”,它们的值分别是“v1”、“v2”、“v3”,调用人人API的应用的私钥Secret Key为“secret_key”,计算方法如下所示。

    注意:这些参数中不包含sig(签名)参数,因为sig参数的值此时没有计算出来。

    • 将请求参数格式化为“key=value”格式,即“k1=v1”、“k2=v2”、“k3=v3”;
    • 将上诉格式化好的参数键值对,以字典序升序排列后,拼接在一起,即“k1=v1k2=v2k3=v3”;
    • 在上拼接好的字符串末尾追加上应用的Secret Key;
    • 上述字符串的MD5值即为签名的值。

    有点小麻烦,下面是我写的发布状态的方法,供参考:

    1. /** 
    2.  * 人人网操作工具类 
    3.  * @author iStar 
    4.  * 
    5.  */  
    6. public class RenrenHelper {  
    7.     public static final String API_URL = "http://api.renren.com/restserver.do";  
    8.   
    9.     private  SharedData share ;  
    10.   
    11.     public RenrenHelper(Context context) {  
    12.         share = new SharedData(context);  
    13.     }  
    14.   
    15.     /** 
    16.      * 更新状态 
    17.      * @param status 状态内容 
    18.      * @return  是否发布成功 
    19.      */  
    20.     public  boolean updateStatus(String status) {  
    21.         boolean success = false;  
    22.         String accessToken = share.getRenrenToken();    //之前获取的accessToken  
    23.         Log.d(GlobalData.TAG, "accessToken:" + accessToken);  
    24.         String requestMethod = "status.set";            //接口名称  
    25.         String v = "1.0";                               //API的版本号,请设置成1.0  
    26.         String url = API_URL;                  //请求人人网开放平台API服务器的地址  
    27.   
    28.         //生成签名  
    29.         StringBuilder sb = new StringBuilder();  
    30.         sb.append("access_token=").append(accessToken)  
    31.             .append("format=").append("JSON")  
    32.             .append("method=").append(requestMethod)  
    33.             .append("status=").append(status)  
    34.             .append("v=").append(v)  
    35.             .append(GlobalData.RENREN_SECRET);  
    36.         String signature = MD5.getMD5(sb.toString());  
    37.         Log.d(GlobalData.TAG, "signature:" + signature);  
    38.   
    39.         PostMethod method = new PostMethod(url);  
    40.   
    41.         //将以上准备好的参数添加到method对象中  
    42.         method.addParameter("access_token", accessToken);  
    43.         method.addParameter("method", requestMethod);  
    44.         method.addParameter("v", v);  
    45.         method.addParameter("status", status);  
    46.         method.addParameter("format""JSON");  //返回结果的形式,支持XML或者JSON两种形式,默认为XML  
    47.         method.addParameter("sig", signature);  
    48.   
    49.         HttpClient client = new HttpClient();  
    50.         try {  
    51.             client.executeMethod(method);  
    52.             String result = method.getResponseBodyAsString();        //返回请求的结果  
    53.             Log.d(GlobalData.TAG, "result:" + result);  
    54.             if (result != null) {  
    55.                 JSONObject json = new JSONObject(result);  
    56.                 String ret = (String) json.get("result");  
    57.                 if (ret != null) {  
    58.                     success = ret.equals("1");  
    59.                 }  
    60.             }  
    61.         } catch (Exception e) {  
    62.             e.printStackTrace();  
    63.         }   
    64.   
    65.         return success;  
    66.     }  
    67. }  

    上面用到了一个生产MD5的方法,下面是我很久以前写的一个生成一个字符串MD5码的类:

    1. import java.security.MessageDigest;  
    2.   
    3. /** 
    4.  * MD5工具类,用于生产字符串的MD5码 
    5.  * @author iStar 
    6.  * 
    7.  */  
    8. public class MD5 {  
    9.   
    10.     public static String getMD5(String s) {  
    11.         try {  
    12.             MessageDigest md5 = MessageDigest.getInstance("MD5");  
    13.   
    14.             byte[] byteArray = s.getBytes("ISO-8859-1");  
    15.             byte[] md5Bytes = md5.digest(byteArray);  
    16.   
    17.             StringBuffer hexValue = new StringBuffer();  
    18.   
    19.             for (int i = 0; i < md5Bytes.length; i++) {  
    20.                 int val = ((int) md5Bytes[i]) & 0xff;  
    21.                 if (val < 16)  
    22.                     hexValue.append("0");  
    23.                 hexValue.append(Integer.toHexString(val));  
    24.             }  
    25.   
    26.             return hexValue.toString();  
    27.   
    28.         } catch (Exception e) {  
    29.             e.printStackTrace();  
    30.             return null;  
    31.         }  
    32.     }  
    33. }  
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 10
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值