转载请标明出处: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认证的到这里就聊完了。