转载请标明出处:http://blog.csdn.net/android_ls/article/details/8748901
声明:关于仿人人项目,我是边看人人官方提供的API,边思考,整理好思路,就开始编写代码。有些地方考虑的不是很全面,大家在阅读的时候,对某些细节的处理,若有什么好的处理方式,欢迎交流。(请注意交流时的用词,文明沟通,谢谢。)
人人授权认证已聊了两篇了,这篇重点是整理思路和重构代码(项目开发过程中开发人员经常干的事)。好了不废话,下面开始聊今天的内容。
一、人人Auth授权认证流程图:
二、重构代码:
1、再次访问授权页出现的空白页,如下图:
解决方法,修改WebView组件的请求重定向方法,处理代码如下:
mWebView.setWebViewClient(new WebViewClient() { public boolean shouldOverrideUrlLoading(WebView webView, String url) { Log.i(TAG, "shouldOverrideUrlLoading() Redirect URL = " + url); if (url.startsWith(Constant.DEFAULT_REDIRECT_URI + "#error=login_denied")) { AuthActivity.this.onBackPressed(); } else if(url.startsWith(Constant.DEFAULT_REDIRECT_URI + "#access_token")) { String accessToken = url.substring(url.indexOf("=")+1, url.indexOf("&")); Log.i(TAG, "accessToken = " + accessToken); // 人人Demo LOG打印: 195789|6.7faefec2274182195287028d00323781.2592000.1367118000-461345584 // 服务器端返回: 195789%7C6.7faefec2274182195287028d00323781.2592000.1367118000-461345584 accessToken = accessToken.replace("%7C", "|"); Log.i(TAG, "Success obtain accessToken = " + accessToken); // 存储AccessToken mAuthTokenManager.storeAccessToken(accessToken); exchangeSessionKey(accessToken); } else { webView.loadUrl(url); } return true; } public void onReceivedSslError(WebView view, SslErrorHandler handler, android.net.http.SslError errorCode) { // 在默认情况下,通过loadUrl(String url)方法,可以顺利load。 // 但是,当load有ssl层的https页面时,如果这个网站的安全证书在Android无法得到认证,WebView就会变成一个空白页, // 而并不会像PC浏览器中那样跳出一个风险提示框。因此,我们必须针对这种情况进行处理。(这个证书限于2.1版本以上的Android 系统才可以) // 默认的处理方式,WebView变成空白页 // handler.cancel(); // 接受证书 handler.proceed(); } @Override public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) { super.onReceivedError(view, errorCode, description, failingUrl); AuthActivity.this.onBackPressed(); } public void onPageStarted(WebView view, String url, Bitmap favicon) { Log.i(TAG, "onPageStarted() URL = " + url); // super.onPageStarted(view, url, favicon); } public void onPageFinished(WebView view, String url) { Log.i(TAG, "onPageFinished() URL = " + url); // super.onPageFinished(view, url); } });
2、将有关认证授权信息提取放到认证信息管理类中,代码如下:
package com.everyone.android;import android.content.Context;import android.content.SharedPreferences;import android.content.SharedPreferences.Editor;import com.everyone.android.entity.Authorization;/** * 功能描述:认证授权信息管理类 * @author android_ls * */public final class AuthTokenManager { private Context mContext; private SharedPreferences mSharedPreferences; public AuthTokenManager(Context context){ this.mContext = context; mSharedPreferences = mContext.getSharedPreferences("auth_config", Context.MODE_PRIVATE); } /** * 获取accessToken * @return */ public String getAccessToken() { String accessToken = mSharedPreferences.getString("oauth_token", null); if (accessToken == null) { return null; } long createTime = mSharedPreferences.getLong("create_oauth_token_time", 0); long life = Long.parseLong(accessToken.split("\\.")[2]) * 1000; long currenct = System.currentTimeMillis(); long oneHour = 1000 * 60 * 60; if ((createTime + life) < (currenct - oneHour)) { Editor editor = mSharedPreferences.edit(); editor.clear(); editor.commit(); return null; } return accessToken; } /** * 存储accessToken, * @param accessToken */ public void storeAccessToken(String accessToken) { Editor editor = mSharedPreferences.edit(); if (accessToken != null) { editor.putString("oauth_token", accessToken); editor.putLong("create_oauth_token_time", System.currentTimeMillis()); } else { editor.clear(); } editor.commit(); } /** * 在本地存储Authorization * @param auth */ public void save(Authorization auth){ Editor editor = mSharedPreferences.edit(); editor.putString("session_key", auth.getSessionKey()); editor.putString("session_secret", auth.getSessionSecret()); editor.putLong("expires_in", auth.getExpiresIn()); editor.putLong("create_session_time", auth.getCreateSessionTime()); // editor.putString("oauth_token", auth.getOauthToken()); editor.putLong("userId", auth.getUserId()); editor.commit(); } /** * 从SharedPreference中读入SessionKey */ private Authorization getAuthBySharedPre() { // String oauthToken = mSharedPreferences.getString("oauth_token", null); String sessionKey = mSharedPreferences.getString("session_key", null); String sessionSecret = mSharedPreferences.getString("session_secret", null); long userId = mSharedPreferences.getLong("userId", 0); long expires = mSharedPreferences.getLong("expires_in", 0); long createTime = mSharedPreferences.getLong("create_session_time", 0); long expireTime = createTime + expires; Authorization auth = new Authorization(); // auth.setOauthToken(oauthToken); auth.setSessionKey(sessionKey); auth.setSessionSecret(sessionSecret); auth.setCreateSessionTime(createTime); auth.setExpiresIn(expireTime); auth.setUserId(userId); return auth; } /** * 检测当前session是否有效 * @return * true - session 有效 * false - session 无效 */ public boolean isSessionValid() { Authorization auth = getAuthBySharedPre(); long current = System.currentTimeMillis(); if(auth.getSessionKey() != null && auth.getSessionSecret() != null && current < auth.getExpiresIn()) { return true; } // sessioin 已过期,删除SharedPreference中存储的SessionKey信息 Editor editor = mSharedPreferences.edit(); editor.clear(); editor.commit(); return false; } }
3、将服务器端返回的授权认证JSON字符串的解析工作提取
package com.everyone.android.parse;import org.json.JSONException;import org.json.JSONObject;import com.everyone.android.entity.Authorization;/** * 功能描述:负责解析Auth认证的JSON字符串 * @author android_ls * */public final class AuthParse { public static Authorization getAuth(String json) throws JSONException { JSONObject jsonObject = new JSONObject(json); JSONObject jsonRenrenToken = jsonObject.getJSONObject("renren_token"); String sessionKey = jsonRenrenToken.getString("session_key"); String sessionSecret = jsonRenrenToken.getString("session_secret"); long expiresIn = jsonRenrenToken.getLong("expires_in"); String oauthToken = jsonObject.getString("oauth_token"); long userId = jsonObject.getJSONObject("user").getLong("id"); // 对Session过期时间进行处理, Session过期时间 = 系统当前的时间 + 服务器端返回的Session过期时间。 long createSessionTime = System.currentTimeMillis(); expiresIn = createSessionTime + expiresIn*1000; // 服务器端返回的Session过期时间单位为秒,因此需要乘以1000 Authorization auth = new Authorization(); auth.setOauthToken(oauthToken); auth.setSessionKey(sessionKey); auth.setSessionSecret(sessionSecret); auth.setCreateSessionTime(createSessionTime); auth.setExpiresIn(expiresIn); auth.setUserId(userId); return auth; } }
4、授权认证界面的处理:
/** * 通过accessToken换取session_key、session_secret和userId * @param accessToken */ private void exchangeSessionKey(String accessToken) { if (accessToken == null || accessToken.length() < 1) { return; } Map<String, String> parameter = new HashMap<String, String>(); parameter.put("oauth_token", accessToken); AsyncBaseRequest asyncRequest = new AsyncHttpPost(Constant.SESSION_KEY_URL, parameter, new ParseCallback (){ @Override public Authorization parse(String json) throws JSONException { Log.i(TAG, "result = " + json); if(!TextUtils.isEmpty(json)){ // 服务器端返回的JSON字符串: /*{ "renren_token": { "session_secret":"52e95c7b02abb0a80a4a80116438063a", "expires_in":2595334, "session_key":"6.8fed55fdfd5c027c2ecb0ac50859f97c.2592000.1367121600-461345584" }, "oauth_token":"195789|6.8fed55fdfd5c027c2ecb0ac50859f97c.2592000.1367121600-461345584", "user": { "id":461345584 } }*/ // 解析JSON Authorization auth = AuthParse.getAuth(json); Log.e(TAG, "auth = " + auth.toString()); return auth; } return null; } }, new ResultCallback(){ @Override public void onSuccess(final Object result) { if (!(result instanceof Authorization)) { Log.e(TAG, "网络请求返回值解析后不是Authorization类型"); return; } // 本地存储Authorization授权认证数据 mAuthTokenManager.save((Authorization)result); mHandler.post(new Runnable() { @Override public void run() { if (mWebView != null) { mWebView.stopLoading(); } Intent intent = new Intent(AuthActivity.this, EveryoneActivity.class); AuthActivity.this.startActivity(intent); AuthActivity.this.finish(); } }); } @Override public void onFail(int errorCode) { Log.e(TAG, "网络请求返回的errorCode = " + errorCode); } }); mDefaultThreadPool.execute(asyncRequest); mAsyncRequests.add(asyncRequest); }
5、导引界面添加的处理:
// 检测accessToken是否有效 String accessToken = mAuthTokenManager.getAccessToken(); LogUtil.i(TAG, "accessToken = " + accessToken); Intent intent = new Intent(); if (accessToken == null) { intent.setClass(this, AuthActivity.class); startActivity(intent); return; } // 检测Session是否有效 if (mAuthTokenManager.isSessionValid()) { intent.setClass(this, EveryoneActivity.class); startActivity(intent); finish(); } else { // accessToken有效,Session失效 exchangeSessionKey(accessToken); }
注:当accessToken有效,Session失效时的处理,与授权界面的通过accessToken换取session_key、session_secret和userId基本一致,就不贴代码了。
6、Auth信息实体类代码:
package com.everyone.android.entity;/** * 功能描述:Auth信息实体类 * @author android_ls * */public class Authorization { private String oauthToken; // accessToken private long userId; // 当前登录用户的uid private String sessionKey; // Session key private String sessionSecret; // Session Secret private long expiresIn; // Session 过期时间 private long createSessionTime; // 创建时间(从服务器端获取到时的本地时间) public String getOauthToken() { return oauthToken; } public void setOauthToken(String oauthToken) { this.oauthToken = oauthToken; } public long getUserId() { return userId; } public void setUserId(long userId) { this.userId = userId; } public String getSessionKey() { return sessionKey; } public void setSessionKey(String sessionKey) { this.sessionKey = sessionKey; } public String getSessionSecret() { return sessionSecret; } public void setSessionSecret(String sessionSecret) { this.sessionSecret = sessionSecret; } public long getExpiresIn() { return expiresIn; } public void setExpiresIn(long expiresIn) { this.expiresIn = expiresIn; } public long getCreateSessionTime() { return createSessionTime; } public void setCreateSessionTime(long createSessionTime) { this.createSessionTime = createSessionTime; } public String toString() { StringBuilder authResult = new StringBuilder(); authResult.append(" oauth_token = ").append(oauthToken); authResult.append("\n session_key = ").append(sessionKey); authResult.append("\n session_secret = ").append(sessionSecret); authResult.append("\n expires_in = ").append(expiresIn); authResult.append("\n userId = ").append(userId); return authResult.toString(); }}
有关人人Auth认证的到这里就聊完了。