zoukankan      html  css  js  c++  java
  • 新浪微博授权认证的实现

      最近准备找工作,着手看了下新浪微博的资料,前几天通过调用客户端实现了微博分享功能。这两天在网上搜了些资料,结合官方的开发文档,实现了授权验证部分。
      下面按类作为章节来总结下验证这部分的实现:
      Constants类
        这个类内容很少,但起到很大作用,能否成功获取授权关键就在于该类中的一些变量如APP_KEY和SECRET的赋值是否正确。

    package com.example.shareweibobyapi;
    //授权类
    public interface Constants {
        /** 当前 DEMO 应用的 APP_KEY,如果自己在新浪官网上的开发者认证还没有通过,则该APP_KEY和SECRET有效期一般只有一天 */
        public static final String APP_KEY      = "2059271021";
        public static final String CONSUMER_SECRET      = "0df386dee39f2b165c066a5665ff4eb7";
        public static final String REDIRECT_URL = "http://www.sina.com.cn";
        public static final String SCOPE = 
                "email,direct_messages_read,direct_messages_write,"
                + "friendships_groups_read,friendships_groups_write,statuses_to_me_read,"
                + "follow_app_official_microblog," + "invitation_write";
    }

      AccessTokenKeeper类
        该类通过SharedPreferences实现了AccessToken的保存和读取以及删除。下面对SharePreferences类进行简单介绍:SharedPreferences是Android平台上一个轻量级的存储类,主要保存一些配置信息,可以保存Long、Int、String类型的数据。2个Activity之间的数据传递除了可以通过Intent来传递,还可以使用该类进行传递。

    package com.example.shareweibobyapi;
    
    import android.content.Context;
    import android.content.SharedPreferences;
    import android.content.SharedPreferences.Editor;
    import com.sina.weibo.sdk.auth.Oauth2AccessToken;
    /**
     * 该类实现了AccessToken的保存和读取以及删除。*/
    public class AccessTokenKeeper {
        
        private static final String PREFERENCES_NAME = "com_weibo_sdk_android";//SharedPreferences类所在包
        private static final String KEY_UID           = "uid";//创建一个变量存储用户昵称
        private static final String KEY_ACCESS_TOKEN  = "access_token";//创建一个变量存储access_token
        private static final String KEY_EXPIRES_IN    = "expires_in";
        
        /**
         * 保存 Token 对象到 SharedPreferences。
         * @param context 应用程序上下文环境
         * @param token   Token 对象
         */
        public static void writeAccessToken(Context context, Oauth2AccessToken token) {
            if (null == context || null == token) {
                return;
            }
            SharedPreferences pref = context.getSharedPreferences(PREFERENCES_NAME, Context.MODE_APPEND);
            Editor editor = pref.edit();
            editor.putString(KEY_UID, token.getUid());
            editor.putString(KEY_ACCESS_TOKEN, token.getToken());
            editor.putLong(KEY_EXPIRES_IN, token.getExpiresTime());
            editor.commit();
        }
    
        /**
         * 从 SharedPreferences 读取 Token 信息。
         * @param context 应用程序上下文环境
         * @return 返回 Token 对象
         */
        public static Oauth2AccessToken readAccessToken(Context context) {
            if (null == context) {
                return null;
            }
            Oauth2AccessToken token = new Oauth2AccessToken();
            SharedPreferences pref = context.getSharedPreferences(PREFERENCES_NAME, Context.MODE_APPEND);
            token.setUid(pref.getString(KEY_UID, ""));
            token.setToken(pref.getString(KEY_ACCESS_TOKEN, ""));
            token.setExpiresTime(pref.getLong(KEY_EXPIRES_IN, 0));
            return token;
        }
        /**
         * 清空 SharedPreferences 中 Token信息。
         * @param context 应用程序上下文环境
         */
        public static void clear(Context context) {
            if (null == context) {
                return;
            }
            SharedPreferences pref = context.getSharedPreferences(PREFERENCES_NAME, Context.MODE_APPEND);
            Editor editor = pref.edit();
            editor.clear();
            editor.commit();
        }
    }

      MainActivity类
        该类为主窗口类,实现了OAuth授权认证。新浪微博的OAuth授权认证过程,大致可以分为以下几个步骤:
          1.第三方应用携带App Key和App Secret两个参数向新浪微博发起认证请求。
          2.通过验证后,第三方应用根据服务器返回的Request Token和Request Secret这两个参数跳转到新浪微博的授权界面。如果用户设备上已经安装微博客户端,则直接调用微博客户端拉取授权信息(oauth_verifier),否则跳转到WEB认证界面,用户可通过输入自己的账号和密码获取授权信息(oauth_verifier)。
          3.第三方应用携带Request Token和Request以及oauth_verifier这三个参数再次向新浪微博发起认证请求。新浪微博将返回user_id、Access Token和Access Secret这三组参数,客户端利用这三组参数即可调用具有相应权限的API。

    package com.example.shareweibobyapi;public class MainActivity extends Activity {
        
        Button ssoBtn;//分享按钮
        EditText shareText;
        private TextView mTokenText;//显示授权成功后返回的access_token
        private WeiboAuth mWeiboAuth;//微博web授权类,提供登录功能
        private Oauth2AccessToken mAccessToken;//提供Oauth2认证功能
        private SsoHandler mSsoHandler;
        private UsersAPI mUsersAPI;//用户信息接口 
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            initView();
        }
        public void initView()
        {
            ssoBtn=(Button) findViewById(R.id.button1);
            mTokenText=(TextView) findViewById(R.id.textView1);
            //创建微博实例,传入APP_KEY,REDIRECT_URL等信息
            mWeiboAuth=new WeiboAuth(this,Constants.APP_KEY,Constants.REDIRECT_URL,Constants.SCOPE);
            //从SharedPreferences读取AccessToken信息
            mAccessToken=AccessTokenKeeper.readAccessToken(this);
            //第一次启动本应用,AccessToken不可用
            if(mAccessToken.isSessionValid())
            {
                updateTokenView(true);
            }
            //单击“分享”按钮,进行授权
            ssoBtn.setOnClickListener(new OnClickListener()
            {
                public void onClick(View v)
                {
                    if(v==ssoBtn)
                    {
                        mSsoHandler=new SsoHandler(MainActivity.this,mWeiboAuth);
                        mSsoHandler.authorize(new AuthListener());
                    }
                }
                
            });
        }
        
        //当SSO授权Activity退出时,该函数被调用.发起SSO登录的Actiity必须重写onActivityResult
        protected void onActivityResult(int requestCode,int resultCode,Intent data)
        {
            super.onActivityResult(requestCode,resultCode,data);
            if(mSsoHandler!=null)
            {
                mSsoHandler.authorizeCallBack(requestCode, resultCode, data);
            }
        }
        
        //微博授权回调类
        class AuthListener implements WeiboAuthListener
        {    //授权完成
            @Override
            public void onComplete(Bundle values){
                //从Bundle解析Token
                mAccessToken=Oauth2AccessToken.parseAccessToken(values);
                if(mAccessToken.isSessionValid())
                {
                    //显示Token
                    updateTokenView(false);
                    //保存Token到SharePreferences
                    AccessTokenKeeper.writeAccessToken(MainActivity.this, mAccessToken);
                    Toast.makeText(MainActivity.this,"success!!",Toast.LENGTH_SHORT).show();
                    //根据uid获取用户的昵称
                    long uid=Long.parseLong(mAccessToken.getUid());
                    mUsersAPI.show(uid,mListener);
                }
                else
                {
                    Toast.makeText(MainActivity.this,"fail!!",Toast.LENGTH_SHORT).show();
                }
            }//授权异常
            @Override
            public void onWeiboException(WeiboException e)
            {
                Toast.makeText(MainActivity.this,  "Auth exception : " + e.getMessage(), Toast.LENGTH_LONG)  
                        .show();
            }
        }
        
        //显示当前Token信息
        public void updateTokenView(boolean hasExisted)
        {    //获取用户信息接口
            mUsersAPI=new UsersAPI(mAccessToken);
            String date=new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").format(new java.util.Date(mAccessToken.getExpiresTime()));
            String format=getString(R.string.weibosdk_demo_token_to_string_format_1);
            mTokenText.setText(String.format(format,mAccessToken.getToken(),date));
            String message=String.format(format,mAccessToken.getToken(),date);
            if(hasExisted)
            {
                message=getString(R.string.weibosdk_demo_token_has_existed)+"
    "+message;
                //根据uid获取用户的昵称,因为uid是在回调方法从服务器传递过俩的数据中
                long uid=Long.parseLong(mAccessToken.getUid());
                mUsersAPI.show(uid, mListener);
            }
            mTokenText.setText(message);
        }
    
        };
    }

    来看看期待已久的授权成功的效果图:

    总结:
      整个过程中遇到的问题以及解决方案:
      1.定义按钮的时候犯了个低级错误:在MainActivity的变量定义区域实例化了一个Button对象,导致运行时出现空指针错误,最后通过LOgcat信息定位错误所在行,将实例化语句转移到OnCreat()中即可解决问题。
      2.运行程序,点击“分享”按钮出现这个异常:auth exception 21338。出现问题后百度、谷歌交叉搜索一下,最后才明白问题根源所在:App_Key过期。由于在新浪微博上申请的开发者身份还没有通过认证,所以申请的App_Key只能在当天使用。找到问题根源,解决起来就很简单了,重新申请一个就搞定。
      3.解决上面那个问题后,满怀信心地再次运行程序,结果却出现这个错误:sso package or sign error。再次百度、谷歌,结果发现这是新版本的SDK才会出现的问题,一般都是由于MD5签名不正确或者过期而导致。而当想要修改MD5签名的时候,我竟然发现一开始创建应用的时候我竟没有使用签名,真是蠢到家。解决起来也很简单,安装一个签名工具,签名后在新浪微博个人信息里面填写下应用报名和签名即可。
    领悟:
      学习一个新的知识,不要太过浮躁,不要总想着我多长时间内能做出来。对于没接触过的东西,即使再简单,对我们来说都是陌生的东西,和陌生的东西打交道总需要些耐心和时间。所以多看看与该知识相关的一些优秀博客,站在别人的成果上去看问题,总会看得更远一些。
      
  • 相关阅读:
    三种实现AJAX的方法以及Vue和axios结合使用的坑
    一个简陋的个人小项目,也是个人第一个真正意义上的独立项目——Graph
    使用docsify并定制以使它更强大
    使用particles.js实现网页背景粒子特效
    使用nginx和tomcat配置反向代理和动静分离
    php (zip)文件下载设置
    php 获取当前完整url地址
    php 实现重定向的三种方式
    php 查看使用多少内存
    linux 查看系统信息
  • 原文地址:https://www.cnblogs.com/dream550/p/3852429.html
Copyright © 2011-2022 走看看