• 通用社区登陆组件技术分享(开源)下篇:OAuth 源码下载及原理解说


    上节内容:

    1:通用社区登陆组件技术分享(开源)上篇:OAuth 授权登陆介绍

    2:通用社区登陆组件技术分享(开源)中篇:OAuth 登陆组件流程及组件集成方法

    本节内容:

    1:简述组件设计的过程及思路及部分重点源码讲解

    2:源码下载

    3:扩展机制说明 

    附源码截图:等会看以下思路时,可以对照着看:

    一:简述组件设计的过程及思路

    1:为什么想到弄成组件?

    当重复的代码或相似的事件>=2个时,我都会想一下,是否还可能有第3个,第4个相近的,如果有,就会统一处理,组件就是设计的再通用一些。

    2:本人设计组件的原则? 

    2.1:让用户以最简单的方式使用或调用组件,编写代码量最小化;

    2.2:所有的设计,都参考第2.1点。

    3:本人组件设计的简单思路过程:(5行代码的设计思路)

    3.1:用户的操作UI设计:

     

    如上图的第三方授权登陆如何展示?

    在html里直接写死?感觉不给力,而且如果扩展多几个第三方登陆时,又要去组合网址,是件麻烦事。

    所以我想到了应该有UI类,应该有个GetHtml(),这样来解决让调用更简单。

    实现UI.GetHtml()方法:
    这里也是有点知识点的,为了让代码简洁化,我花了不少时间思考,通过良好的代码组合设计,减少代码量的编写。

    于是,我用了一个常用方法,来优化这种设计:

            public static string GetHtml()
            {
                string link = "<a href=\"{0}\" target=\"_blank\"><img src=\"{1}\" /></a>";
                StringBuilder sb = new StringBuilder();
                foreach (KeyValuePair<string,OAuth2Base> ob in OAuth2Factory.ServerList)
                {
                    if (!string.IsNullOrEmpty(ob.Value.AppKey))
                    {
                        sb.AppendFormat(link, string.Format(ob.Value.OAuthUrl, ob.Value.AppKey,System.Web.HttpUtility.UrlEncode(ob.Value.CallbackUrl), ob.Key), ob.Value.ImgUrl);
                    }
                }
                return sb.ToString();

             } 

    这段代码里,包含了几种优化思路:

    1:应该有一个方法,可以获取当前所有的授权类型: OAuth2Factory.ServerList

    2:授权类型应该包括一些配置项,可以直接读取: ob.Value.OAuthUrl, ob.Value.AppKey,ob.Value.ImgUrl

    在想出这种方法时,还没开始设计OAuth2授权相关类,所以当时还只是伪代码,随着OAuth2类被完善,这里的代码就简单成型了。

    OK,让我们回头看看:

    3.2:OAuth授权类设计(传说的抽象+工厂):

    和数据库多数据库支持的设计思路如出一折。

    1:应该有个基类:OAuth2Base(包括通用的方法和属性)

    2:继续基类 OAuth2Base,实现不同的授权:SinaWeiboOAuth、QQAuth、其它...等!

    3:有个工厂OAuth2Factory来返回当前的授权类型(正如数据库组件来设计当前是操作哪种数据库类型)

    4:有个小工具类Tool,放几个常用的小方法。

    在OAuth2Factory里,我们通过预先注册所有的子类授权,来汇总所有的授权类型。

    所以GetHtml里可以获取所有授权类型进行遍历组装。

    代码:

            static Dictionary<string, OAuth2Base> _ServerList;
            /// <summary>
            
    /// 获取所有的类型(新开发的OAuth2需要到这里注册添加一下)
            
    /// </summary>
            internal static Dictionary<string, OAuth2Base> ServerList
            {
                get
                {
                    if (_ServerList == null)
                    {
                        _ServerList = new Dictionary<string, OAuth2Base>(StringComparer.OrdinalIgnoreCase);
                        _ServerList.Add(OAuthServer.SinaWeiBo.ToString(), new SinaWeiBoOAuth());//新浪微博
                        _ServerList.Add(OAuthServer.QQ.ToString(), new QQOAuth());//QQ微博
                    }
                    return _ServerList;
                }

    } 


    整体的设计并不复杂,只要实现后,就可以实现授权,并得到第三方的token和openid数据。

    到这里,并未实现绑定账号,于是我开始思考:

    3.3 OAuth2 绑定网站的账号实现第三方登陆:

    如何和自己的网站的账号实现绑定?

    在原来网站的数据库里,添加字段?或者创建新表,再进行设计?

    考虑到这样的设计,和网站代码结合度必然很深,不可能做到通用型,而且不同网站,用的是不同的数据库,那得编写多少种不同的脚本?

    所以思前想后,将数据外置存储在外部文本,考虑到CYQ.Data V5已经接近完美的支持文本数据库及CodeFirst操作,所以引用它做为默认的外置数据库操作类。

    当然拿到源码后,如果对于外存储过块需要调整或使用其它框架,这个自行操作了,不干涉内政。 

    内置的文本数据库解决方案:

    如果对比上面的源码截图,你应该发现,所以类都提到了,只剩下最后一个:OAuth2Account ,它就是实现和网站绑定的罪人。

    代码也很简单的说(除了继承自OrmBase和构造函数指定了表名和文本存储路径,基本上就是一个常见的实体类了):

    public class OAuth2Account:CYQ.Data.Orm.OrmBase
        {
            public OAuth2Account()
            {
                base.SetInit(this"OAuth2Account""Txt Path={0}App_Data");
            }
            private int _ID;

            public int ID
            {
                get
                {
                    return _ID;
                }
                set
                {
                    _ID = value;
                }
            }
            private string _OAuthServer;
            /// <summary>
            
    /// 授权的服务类型
            
    /// </summary>
            public string OAuthServer
            {
                get
                {
                    return _OAuthServer;
                }
                set
                {
                    _OAuthServer = value;
                }
            }
            private string _Token;
            /// <summary>
            
    /// 保存的Token
            
    /// </summary>
            public string Token
            {
                get
                {
                    return _Token;
                }
                set
                {
                    _Token = value;
                }
            }
            private string _OpenID;
            /// <summary>
            
    /// 保存对应的ID
            
    /// </summary>
            public string OpenID
            {
                get
                {
                    return _OpenID;
                }
                set
                {
                    _OpenID = value;
                }
            }
            private string _BindAccount;
            
            private DateTime _ExpireTime;
            /// <summary>
            
    /// 过期时间
            
    /// </summary>
            public DateTime ExpireTime
            {
                get
                {
                    return _ExpireTime;
                }
                set
                {
                    _ExpireTime = value;
                }
            }

            private string _NickName;
            /// <summary>
            
    /// 返回的第三方昵称
            
    /// </summary>
            public string NickName
            {
                get
                {
                    return _NickName;
                }
                set
                {
                    _NickName = value;
                }
            }
            private string _HeadUrl;
            /// <summary>
            
    /// 返回的第三方账号对应的头像地址。
            
    /// </summary>
            public string HeadUrl
            {
                get
                {
                    return _HeadUrl;
                }
                set
                {
                    _HeadUrl = value;
                }
            }


            /// <summary>
            
    /// 绑定的账号
            
    /// </summary>
            public string BindAccount
            {
                get
                {
                    return _BindAccount;
                }
                set
                {
                    _BindAccount = value;
                }
            }

    在OAuth2Base基类里有两个和内置文本数据库打交首的函数:GetBindAccount和SetBindAccount:

            /// 添加绑定账号
            
    /// </summary>
            
    /// <param name="bindAccount"></param>
            
    /// <returns></returns>
            public bool SetBindAccount(string bindAccount)
            {
                bool result = false;
                if (!string.IsNullOrEmpty(openID) && !string.IsNullOrEmpty(token) && !string.IsNullOrEmpty(bindAccount))
                {
                    using (OAuth2Account oa = new OAuth2Account())
                    {
                        if (!oa.Exists(string.Format("OAuthServer='{0}' and OpenID='{1}'", server, openID)))
                        {
                            oa.OAuthServer = server.ToString();
                            oa.Token = token;
                            oa.OpenID = openID;
                            oa.ExpireTime = expiresTime;
                            oa.BindAccount = bindAccount;
                            oa.NickName = nickName;
                            oa.HeadUrl = headUrl;
                            result = oa.Insert(CYQ.Data.InsertOp.None);
                        }
                    }
                }
                return result;
            }

    由于是CodeFirst及设计的是文本数据库,所以不用去兼容不同网站的数据库,自动生成文本数据库外置,只需要好好玩这个实体就可以了。

    简单的就介绍到这了,设计并不复杂,代码量并不多,方法和成员也很少。

    二:源码下载

    源码点击下载:  OAuth2_Source.rar(download times)

    三:扩展机制说明 

    看完本文,下完源码,也许您可能会有以下功能需要进行调整,这里给出指导与说明:

    1:界面UI的调整,具体看UI类,改动下即可。

    2:增加授权种类:继承OAuth2Base,参考已有的新浪微博和QQ进行操作,当然也可以联系我让我添加。

    3:如何取得绑定后的表数据:只要调用new  OAuth2Account().Select().Bind(列表);

    4:更换授权存储介质,有两种方式:

    a:保留CYQ.Data V5版本,更换数据库,只需要修改OAuth2Account类的构造函数的数据库链接更换为您现在使用的数据库链接即可。

    CYQ.Data V5版本目前仅支持以下数据库(mssql、mysql、oracle、aceess、sqlite、txt、xml),前三种需要授权使用,后四种免费使用。

    b:移除CYQ.Data V5版本,更换底层组件,您只要重写OAuth2Base中的 SetBindAccount和GetBindAccount两个方法即可,然后自己另外存储数据介质。

    不管是哪种,对于有点开发经验的新老手来说,都是相对比较简单。


    51cto大赛的参赛页面,感谢路过的朋友也顺手扔一票:http://blog.51cto.com/contest2012/2127378  

  • 相关阅读:
    高级搜索
    Hibernate通过什么方法可以把私有成员变量赋值成数据库查询到的值然后返回POJO对象呢?
    hibernate继承关系映射和java反射机制的运用
    eclipse启动停止--jdk环境变量配置
    visual studio 正则表达式 查找 替换
    常用正则表达式
    解决兼容的方法!
    JS的定时器和JS的执行机制
    2020年3月2日随笔
    2020年2月12日 线上笔记
  • 原文地址:https://www.cnblogs.com/cyq1162/p/2756848.html
Copyright © 2020-2023  润新知