package com.weibo.sdk.android.sso; import android.app.Activity; import android.content.ActivityNotFoundException; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ResolveInfo; import android.content.pm.Signature; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.os.RemoteException; import android.text.TextUtils; import android.util.Log; import android.widget.Toast; import com.emop.client.Constants; import com.emop.client.WebLoginActivity; import com.emop.client.io.FmeiClient; import com.emop.client.tasks.GetSinaUserInfoTask; import com.sina.sso.RemoteSSO; import com.weibo.net.AccessToken; import com.weibo.net.Oauth2AccessToken; import com.weibo.net.Token; import com.weibo.net.Weibo; /** * 该类用于处理sso 认证功能,通过sso,无需输入用户名、密码即可以通过微博账号访问经过授权的第三方应用,\r\n * 使用SSO登录前,请检查手机上是否已经安装新浪微博客户端,目前仅3.0.0及以上微博客户端版本支持SSO; * 如果未安装,将自动转为Oauth2.0进行认证 * * @author xiaowei6@staff.sina.com.cn * */ public class SsoHandler { public static final int START_WEB_LOGIN = 2001; public static final int SSO_LOGIN_ERROR = 2002; private ServiceConnection conn = null; private static final int DEFAULT_AUTH_ACTIVITY_CODE = 32973; private static final String WEIBO_SIGNATURE = "30820295308201fea00302010202044b4ef1bf300d" + "06092a864886f70d010105050030818d310b300906035504061302434e3110300e0603550408130" + "74265694a696e673110300e060355040713074265694a696e67312c302a060355040a132353696e" + "612e436f6d20546563686e6f6c6f677920284368696e612920436f2e204c7464312c302a0603550" + "40b132353696e612e436f6d20546563686e6f6c6f677920284368696e612920436f2e204c746430" + "20170d3130303131343130323831355a180f32303630303130323130323831355a30818d310b300" + "906035504061302434e3110300e060355040813074265694a696e673110300e0603550407130742" + "65694a696e67312c302a060355040a132353696e612e436f6d20546563686e6f6c6f67792028436" + "8696e612920436f2e204c7464312c302a060355040b132353696e612e436f6d20546563686e6f6c" + "6f677920284368696e612920436f2e204c746430819f300d06092a864886f70d010101050003818" + "d00308189028181009d367115bc206c86c237bb56c8e9033111889b5691f051b28d1aa8e42b66b7" + "413657635b44786ea7e85d451a12a82a331fced99c48717922170b7fc9bc1040753c0d38b4cf2b2" + "2094b1df7c55705b0989441e75913a1a8bd2bc591aa729a1013c277c01c98cbec7da5ad7778b2fa" + "d62b85ac29ca28ced588638c98d6b7df5a130203010001300d06092a864886f70d0101050500038" + "181000ad4b4c4dec800bd8fd2991adfd70676fce8ba9692ae50475f60ec468d1b758a665e961a3a" + "edbece9fd4d7ce9295cd83f5f19dc441a065689d9820faedbb7c4a4c4635f5ba1293f6da4b72ed3" + "2fb8795f736a20c95cda776402099054fccefb4a1a558664ab8d637288feceba9508aa907fc1fe2" + "b1ae5a0dec954ed831c0bea4"; // private String[] mAuthPermissions; private int mAuthActivityCode; private static String ssoPackageName = "";// "com.sina.weibo"; private static String ssoActivityName = "";// "com.sina.weibo.MainTabActivity"; //private WeiboAuthListener mAuthDialogListener; //private Oauth2AccessToken mAccessToken = null; private Activity mAuthActivity; private Weibo mWeibo; public SsoHandler(Activity activity, Handler handler) { mAuthActivity = activity; if(handler != null){ this.handler = handler; } mWeibo = Weibo.getInstance(); mWeibo.setupConsumerConfig(Constants.SINA_APPID, Constants.SINA_APPKEY); mWeibo.setRedirectUrl(Constants.SINA_CALLBACK); //Weibo.isWifi=Utility.isWifi(activity); conn = new ServiceConnection() { @Override public void onServiceDisconnected(ComponentName name) { /** * 为啥在Disconnected的时候启动登陆窗口? */ //mWeibo.startAuthDialog(mAuthActivity, mAuthDialogListener); } @Override public void onServiceConnected(ComponentName name, IBinder service) { RemoteSSO remoteSSOservice = RemoteSSO.Stub.asInterface(service); try { ssoPackageName = remoteSSOservice.getPackageName(); ssoActivityName = remoteSSOservice.getActivityName(); boolean singleSignOnStarted = startSingleSignOn( mAuthActivity, Constants.SINA_APPID, new String[]{}, mAuthActivityCode); if (!singleSignOnStarted) { startWebLogin(); } } catch (RemoteException e) { e.printStackTrace(); } } }; } /** * 进行sso认证 * * @param activity 发起认证的Activity * * @param listener 用于接收认证信息的监听者 public void authorize( final WeiboAuthListener listener) { authorize( DEFAULT_AUTH_ACTIVITY_CODE, listener); } */ public void authorize() { mAuthActivityCode = DEFAULT_AUTH_ACTIVITY_CODE; boolean bindSucced = false; //mAuthDialogListener = listener; // Prefer single sign-on, where available. bindSucced = bindRemoteSSOService(mAuthActivity); // Otherwise fall back to traditional dialog. if (!bindSucced) { startWebLogin(); } } public void startWebLogin(){ Intent intent = new Intent(); intent.setClass(mAuthActivity, WebLoginActivity.class); Message msg = handler.obtainMessage(START_WEB_LOGIN); handler.sendMessage(msg); mAuthActivity.startActivity(intent); } private boolean bindRemoteSSOService(Activity activity) { Context context = activity.getApplicationContext(); Intent intent = new Intent("com.sina.weibo.remotessoservice"); return context.bindService(intent, conn, Context.BIND_AUTO_CREATE); } private boolean startSingleSignOn(Activity activity, String applicationId, String[] permissions, int activityCode) { boolean didSucceed = true; Intent intent = new Intent(); intent.setClassName(ssoPackageName, ssoActivityName); intent.putExtra("appKey", Constants.SINA_APPID);// applicationId //"2745207810" intent.putExtra("redirectUri", Constants.SINA_CALLBACK); if (permissions.length > 0) { intent.putExtra("scope", TextUtils.join(",", permissions)); } // validate Signature if (!validateAppSignatureForIntent(activity, intent)) { return false; } try { activity.startActivityForResult(intent, activityCode); } catch (ActivityNotFoundException e) { didSucceed = false; } activity.getApplication().unbindService(conn); return didSucceed; } private boolean validateAppSignatureForIntent(Activity activity, Intent intent) { ResolveInfo resolveInfo = activity.getPackageManager().resolveActivity( intent, 0); if (resolveInfo == null) { return false; } String packageName = resolveInfo.activityInfo.packageName; try { PackageInfo packageInfo = activity.getPackageManager() .getPackageInfo(packageName, PackageManager.GET_SIGNATURES); for (Signature signature : packageInfo.signatures) { if (WEIBO_SIGNATURE.equals(signature.toCharsString())) { return true; } } } catch (NameNotFoundException e) { return false; } return false; } /** * 重要:发起认证的Activity必须重写onActivityResult, 这个方法必须在onActivityResult 方法内调用, * 例如:<br/> * * @Override * protected void onActivityResult(int requestCode, int resultCode, Intent data) {<br/> * super.onActivityResult(requestCode, resultCode, data);<br/> * if(mSsoHandler!=null){<br/> * mSsoHandler.authorizeCallBack(requestCode, resultCode, data);<br/> * }<br/> * } */ public void authorizeCallBack(int requestCode, int resultCode, Intent data) { if (requestCode == mAuthActivityCode) { // Successfully redirected. if (resultCode == Activity.RESULT_OK) { // Check OAuth 2.0/2.10 error code. String error = data.getStringExtra("error"); if (error == null) { error = data.getStringExtra("error_type"); } // error occurred. if (error != null) { if (error.equals("access_denied") || error.equals("OAuthAccessDeniedException")) { Log.d("Weibo-authorize", "Login canceled by user."); } else { String description = data.getStringExtra("error_description"); if (description != null) { error = error + ":" + description; } Log.d("Weibo-authorize", "Login failed: " + error); } Message msg = handler.obtainMessage(SSO_LOGIN_ERROR); msg.obj = error; handler.sendMessage(msg); } else { String token = data.getStringExtra("access_token"); String expires_in = data.getStringExtra("expires_in"); AccessToken accessToken = new AccessToken(token, Weibo.getAppSecret()); long expired = System.currentTimeMillis() + Long.parseLong(expires_in) * 1000L; accessToken.setExpiresIn(expired); if(isSessionValid(accessToken)){ FmeiClient client = FmeiClient.getInstance(null); client.saveSettings(Constants.PREFS_SINA_ACCESS_TOKEN, token); client.saveSettings(Constants.PREFS_SINA_EXPIRES_IN, expires_in); Weibo.getInstance().setAccessToken(accessToken); String userId = data.getStringExtra("uid"); Log.d("Weibo-authorize", "user id:" + userId); new GetSinaUserInfoTask(token, userId, mAuthActivity, handler).start(); }else { //Log.d("weibo", "expires in:" + (System.currentTimeMillis() + Integer.parseInt(expires_in) * 1000L) + ", x:" + (Long.parseLong(expires_in) * 1000L)); //Log.d("Weibo-authorize", "error access token:" + token + ", expired in:" + expires_in + ", e:" + accessToken.getExpiresIn() + ", cur:" + System.currentTimeMillis()); startWebLogin(); } } } else if (resultCode == Activity.RESULT_CANCELED) { if (data != null) { String msg = data.getStringExtra("error"); } else { Log.d("Weibo-authorize", "Login canceled by user."); } Message msg = handler.obtainMessage(SSO_LOGIN_ERROR); handler.sendMessage(msg); } } } public boolean isSessionValid(Token mAccessToken) { if (mAccessToken != null) { return (!TextUtils.isEmpty(mAccessToken.getToken()) && (mAccessToken.getExpiresIn() == 0 || (System .currentTimeMillis() < mAccessToken.getExpiresIn()))); } return false; } private Handler handler = new Handler(){ public void handleMessage(final Message msg) { String message = null; if(msg.obj != null){ message = msg.obj.toString(); if(message != null){ Toast.makeText(mAuthActivity, message, Toast.LENGTH_LONG).show(); } } if(msg.what == GetSinaUserInfoTask.LOGIN_DONE){ } } }; }