Android仿人人客户端(v5.7.1)——Auth授权认证(整理流程,重构代码)

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值