• mojoPortal集成第三方登录


    概述

    大概花了两个下午加一个晚上完成了对mojoPortal 项目的新浪微博登录的集成。主要时间并非花在如何使用新浪微博登录这个工作上,这一方面在应该说本身不存在太大的问题。而花了这么长时间的确出乎我的意料,再回过头来看看这个过程,主要是花费了大量时间来研究mojoPortal项目的组织结构上面。由于之前也没仔细研究mojoPortal项目的结构所以集成起来的确会慢很多。确实网上对于这个项目的介绍或者开发方式涉及的并不多,因此,我把这个过程记录下来,如果有使用mojoPortal项目的同学,可以节省很多时间。

    目标

    我们在使用mojoPortal项目的时候,可以看到SiteSettings.aspx页面的设置中其实已经有第三方集成登录的选项了,如图2.1所示:

    clip_image002

    图 2.1 Windows Live登录设置

    我们只需要把Windows Live 提供给我们的App Key填进去,然后允许认证就好啦,很方便吧!我们要做的就是加一个新浪微博的选项卡如下:


    图 2.2 新浪微博登录设置

    这样,我们也可以打个勾填个Key和Secret就能开启新浪微博登录了,也可以很方便的关闭新浪微博登录,酷!当我们开启选项后,就可以在登录页面看到新浪微博登录的链接了,如下图2.3:

    clip_image006

    图 2.3 登录页面

    通过新浪微博登录后就可以到我们自己的网站上去啦,如果是第一次从第三方登录,则新建一个系统的账户并把它与第三方账号联系起来(即使通过授权也无法获取新浪微博的注册邮箱,因此不得不在用户第一次连接我们网站时要求填写邮箱)。

    实现

    a) 添加新浪微博设置选项卡

    b) 存储信息到数据库

    c) 添加新浪登录按钮

    d) 新浪验证回调页面处理

    e) 创建第三方登录补充页面

    a) 添加新浪微博选项卡

    首先找到网站设置页面SiteSettings.aspx,在mojoPortal.Web项目的Admin目录下。根据图2.1与2.2中所示,第三方登录包含于安全选项卡中,而页面的整个选项卡结构如下图所示:

    clip_image008

    图 3.1 设置页面的选项卡

    很快我们可以定位到id为tabSecruity的层中,它是由头部的子选项卡与每个选项卡对应的设置选项组成的。我们很清楚的看到上面的一个li列表项对应下面的一个div层,如图3.2,我们对着Windows Live列表项与选项卡依葫芦画瓢,这样就可以得到图3.3的样子。

    clip_image010

    图 3.2 安全选项卡中全貌

    clip_image012

    图 3.3 添加新浪微博登录后的安全选项卡

    很简单,不是吗?下图是新浪微博展开代码:

    image

    图 3.4 新浪微博详细设置项

    我们再来看一下代码中的属性。

    1. mojoPortal项目中class值为settingrow的div即一个设置项,每一个设置项包含一个Label在和一个Input(CheckBox, TextBox等等),如果有必要,还会包含一个查看帮助的小问号;
    2. <mp:SiteLabel>是一个用户自定义控件,我们查看页面头部并未发现有注册tagPrefix 为mp的条目,因此它应该是全局的。我们打开Web.Config可以看到<controls>选项卡中有一个相关条目:
      <add tagPrefix="mp" namespace="mojoPortal.Web.Controls" assembly="mojoPortal.Web.Controls" />
           
      这里显然指定了mojoPortal.Web.Controls 程序集,我们到对应项目中查找确实有名为SiteLabel的类。些类并未做太多工作,主要是ConfigKey属性作为资源文件里面的Key来获取本地语言版本;
    3. <portal:mojoHelpLink> 即为帮助链接,同样的方法在mojoPortal.Web项目中Controls文件夹中找到对应类。

    b) 存储信息到数据库

    接下去要做的就是把第三方平台的配置信息存入数据库,我们在mp_sites数据表中找到有WindowsLiveAppID和WindowsLiveKey字段,同样我们也把新浪的AppKey及AppSecret存储到这个表中,别忘记了添加是否允许新浪微博注册的字段。数据库更新脚本我就不贴了,另外改动表结构之后,会涉及到数据访问层及业务层的更改,主要是SiteSettings这个类,这项工作很简单完全不费脑子!改好后去后台页面找到PopulateLabels()及LoadSettings()函数,顾明思义,作了些把标签进行本地化显示和加载设置的工作,添加以下几个地方:
    第一、找到 liWindowsLive.Visible=false;这一行并在下面添加两行 liSinaWeibo.Visible = false; tabSinaWeibo.Visible = false;其中 liSinaWeibo及tabSinaWeibo为前面页面中定义的列表项及选项卡的ID;
    第二、找到 if (WebConfigSettings.EnableWindowsLiveAuthentication)这一行,以同样的形式添加语句块:
     if (WebConfigSettings.EnableSinaWeiboAuthentication)
    {
    chkAllowSinaWeiboAuth.Checked = selectedSite.AllowSinaWeiboAuth;
    txtSinaWeiboAppKey.Text = selectedSite.SinaWeiboAppKey;
    txtSinaWeiboAppSecret.Text = selectedSite.SinaWeiboAppSecret;
    }
    并在最后的else中加入
     chkAllowSinaWeiboAuth.Checked = false;
    chkAllowSinaWeiboAuth.Enabled = false;
    其中三个对象看名字就明白了。selectedSites是SiteSettings对象,它是当前选择的站点设置,这里可以直接获取里面的三个刚才添加的属性,这两个语句块主要检测Web.Config文件中是否允许新浪微博登录如果允许即把数据库值绑定到控件,因此我们必须在Web.Config文件中找到EnableOpIDAuthentication在其下面加入如下节点:
     <add key="EnableSinaWeiboAuthentication" value="true"/>
    为了能够使程序获取到配置项,我们还要更改WebConfigSettings类,它在mojoPortal.Web项目的Components文件夹中,我们要为类实现一个get访问器:
     public static bool EnableSinaWeiboAuthentication
    {
    get { return
    ConfigHelper.GetBoolProperty("EnableSinaWeiboAuthentication", false);
    }
    }
     
    
    第三、找到
     litWindowsLiveTabLink.Text = "<a href='#" + tabWindowsLiveID.ClientID + "'>"+ Resource.SiteSettingsSecurityWindowsLiveTab + "</a>";
    在其后面添加语句:
     litSinaWeiboTabLink.Text = "<a href='#" + tabSinaWeibo.ClientID + "'>" + Resource.SiteSettingsSecuritySinaWeiboTab + "</a>";
    这句话主要从资源文件加载本地化的标签名字,我们需要在资源文件中添加相应的值,这个就不详说了。
     
    第四、在btnSave_Click事件中加入如下代码块:
     if (WebConfigSettings.EnableSinaWeiboAuthentication)
    {
    selectedSite.AllowSinaWeiboAuth = chkAllowSinaWeiboAuth.Checked;
    selectedSite.SinaWeiboAppKey = txtSinaWeiboAppKey.Text;
    selectedSite.SinaWeiboAppSecret = txtSinaWeiboAppSecret.Text;
    }
    这样,我们在文本框中填入的数据就可以保存到数据库啦啦!快申请一下新浪微博的AppKey吧。

    c) 编写新浪登录控件

    在mojoPortal.Web项目中Controls文件夹下添加SinaWeiboLoginControl.ascx,前台页面结构如图3.5所示,其中三个地方需要后台加载,是否使用https协议,新浪给的AppKey及回调地址。由于mojoPortal项目中把页面的AutoEventWireup属性都设置成了false,因此我们就入乡随俗吧,同样把SinaWeiboLoginControl.ascx控件的这个属性设置为false,并在后台手动把事件加入事件链。

    image

    图 3.5 新浪登录用户自定义控件

    控件的后台代码实现思路与项目中的WindowsLiveLoginControl.ascx控件一样,先写一个Page_Load函数,在页面OnInit时把Page_Load放到base.Load事件上即可,Page_Load完成的工作是  加载前台需要的三个参数->处理返回地址(这其中的CallBackUrl页面我们在 d) 步骤中添加)。Page_Load与LoadSettings具体代码实现如下:

     protected void Page_Load(object sender, EventArgs e)
    {
    LoadSettings();
    if (
    (!WebConfigSettings.EnableSinaWeiboAuthentication) ||
    (!siteSettings.AllowSinaWeiboAuth)
    )
    {
    this.Visible = false;
    return;
    }
    //处理回调地址
    callbackUrl = SiteUtils.GetNavigationSiteRoot() + "/Secure/SinaWeiboAuthHandler.aspx";
    if (callbackUrl.StartsWith("http://")
    &&protocol.StartsWith("https://")
    )
    callbackUrl.Replace("http://", protocol);
    if (!IsPostBack)
    {
    /*设置返回路径*/
    string returnUrl = WebConfigSettings.PageToRedirectToAfterSignIn;
    if (returnUrl.EndsWith(".aspx"))
    {
    CookieHelper.SetCookie(returnUrlCookieName, returnUrl);
    return;
    }
    if (Page.Request.UrlReferrer != null)
    {
    returnUrl = Page.Request.UrlReferrer.ToString();
    }
    string returnUrlParam = Page.Request.Params.Get("returnurl");
    if (!String.IsNullOrEmpty(returnUrlParam))
    {
    returnUrl = Page.ResolveUrl(Page.Server.UrlDecode(returnUrlParam));
    }
    if (returnUrl.Length > 0)
    {
    CookieHelper.SetCookie(returnUrlCookieName, returnUrl);
    }
    }
    }
    
     /// <summary>
    /// 加载设置项
    /// </summary>
    protected void LoadSettings()
    {
    siteSettings = CacheHelper.GetCurrentSiteSettings();//加载网站配置
    if (SiteUtils.SslIsAvailable()) protocol = "https://";
    else protocol = "http://";
    /*全局配置优先,如果无全局配置则使用当前站点的"新浪"的配置*/
    sinaWeiboAppKey = siteSettings.SinaWeiboAppKey;
    sinaWeiboAppSecret = siteSettings.SinaWeiboAppSecret;
    if (ConfigurationManager.AppSettings["GlobalSinaWeiboAppKey"] != null)
    {
    string globalSinaWeiboAppKey=
     ConfigurationManager.AppSettings["GlobalSinaWeiboAppKey"].Trim();
    if (globalSinaWeiboAppKey.Length > 0)
    sinaWeiboAppKey = globalSinaWeiboAppKey;
    }
    if (ConfigurationManager.AppSettings["GlobalSinaWeiboAppSecret"] != null)
    {
    string globalSinaWeiboAppSecret = 
     ConfigurationManager.AppSettings["GlobalSinaWeiboAppSecret"].Trim();
    if (globalSinaWeiboAppSecret.Length >= 0)
    sinaWeiboAppSecret = globalSinaWeiboAppSecret;
    }
    if (sinaWeiboAppKey.Length == 0 || sinaWeiboAppSecret.Length == 0)
    this.Visible = false;
    }

    d) 添加新浪登录按钮

    查看mojoPortal.Web项目中Secure文件夹下的Login.aspx页面,结构如图3.6。其中包含了两个部分一个是所谓的 StardardLogin也就是系统自己的标准登录,另外的就是第三方登录了。图3.5中已把新浪微博控件添加到页面中,并在页面头部进行了注册如图3.7,加载的控件就是刚 b) 中编写的新浪登录控件。

    image

    图 3.6 登录页面结构

    image

    图 3.7 页面头部的注册信息

    d)  新浪验证回调页面处理

    用户在通过新浪的认证后,便会把access_token,uid等回传给之前设定的回调页面。在Secure文件夹下添加一个页面命名为SinaWeiboAuthHandler.aspx,我们把它作为回调页面。我们在通过新浪登录验证后就加载到如下的Url:

    /Secure/SinaWeiboAuthHandler.aspx#access_token=2.00W88&expires_in=86400&remind_in=54572&uid=1299708822

    很不幸的是,这里用的是“#”而不是“?”,因此,我们在后台是无法直接获取到后面的参数的,我们只能用javascript来把参数过虑出来,再提交给后台做想做的事情。js代码很简单,就不贴了。而后台需要判断本次登录的用户是本站新用户还是老用户,如果是新用户,就让用户去RegisterWithSinaWeiboID.aspx(在步骤 e) 中建立)填邮箱;否则登录成功直接跳转。后台的Page_Load代码如下:

     protected void Page_Load(object sender, EventArgs e)
    {
    LoadParams();
    if (urlParams.Count > 0
    && urlParams["accessToken"] != null
    && urlParams["uid"] != null
    )
    {
    weiboCookieName = "sinaWeibo"
    + siteSettings.SiteId.ToString(CultureInfo.InvariantCulture);
    CookieHelper.SetCookie(weiboCookieName, urlParams["accessToken"]);
    Guid userGuid = SiteUser.GetUserGuidFromSinaWeiboId(siteSettings.SiteId
    , urlParams["uid"]);
    SiteUser usr = new SiteUser(siteSettings,userGuid);
    if(userGuid==Guid.Empty)
    WebUtils.SetupRedirect(
    this,
    SiteUtils.GetNavigationSiteRoot() +
    "/Secure/RegisterWithSinaWeiboID.aspx?uid=" + urlParams["uid"]);
    else
    {
    FormsAuthentication.SetAuthCookie(usr.Name, false);
    WebUtils.SetupRedirect(this,
    SiteUtils.GetNavigationSiteRoot());
    }
    }
    }

    e) 创建第三方登录补充页面

    前面提到,由于无法获取到用户邮箱地址,我们必须在用户第一次登录时迫使他们去填写邮箱。我们创建RegisterWithSinaWeiboID.aspx页面来完成这项工作。到这一步时,我们开始使用新浪微博的SDK,我这里用的是 AMicroblogAPI 。注意到作者在其指导页面上有这样一个步骤:

    image

    图 3.8 作者要求的配置文件

    很明显,我们无法满足这个要求,我们从数据库获取信息并非从配置文件,那如果配置文件中没有对应配置项,会抛出异常吗?带着这个疑问把源码下载后查看,果不其然,如果无法加载配置文件,刚会抛出异常,这并不是我们想要的。

     static Environment()
    {
    var section = ConfigurationManager.GetSection("amicroblogAPI")
    as AMicroblogAPIConfigurationSection;
    if (null != section)
    {
    Environment.ResponseErrorHandlingEnabled =
    section.ResponseErrorHandlingConfig.Enabled;
    Environment.Configuration = section;
    foreach (HandlerConfigurationElement element in section.ResponseErrorHandlingConfig)
    {
    if(string.IsNullOrEmpty(element.Type))
    throw new AMicroblogException(
    LocalErrorCode.ArgumentNotProvided,
    "Handler type not provided in responseErrorHandling configuration section."
    );
    var type = Type.GetType(element.Type, true, true);
    var errorCode = element.ErrorCode;
    if (string.IsNullOrEmpty(errorCode))
    errorCode = "*";
    var interfaceName = "IResponseErrorHandler";
    var inter = type.GetInterface(interfaceName, false);
    if (null == inter)
    throw new AMicroblogException(
    LocalErrorCode.ArgumentInvalid, "Type '{0}' does not implement {1}.",
    element.Type, interfaceName
    );
    ResponseErrorHandlers.Add(new HandlerConfiguration()
    { Type = type, ErrorCode = errorCode });
    }
    if (Environment.ResponseErrorHandlingEnabled)
    {
    Environment.ResponseError +=
    new EventHandler<ResponseErrorEventArgs>(HandleResponseError);
    }
    }
    AppKey = ConfigurationManager.AppSettings["appKey"];
    AppSecret = ConfigurationManager.AppSettings["appSecret"];
    RedirectUri = ConfigurationManager.AppSettings["redirectUri"];
    if (string.IsNullOrEmpty(AppKey) || string.IsNullOrEmpty(AppSecret))
    {
    throw new AMicroblogException(
    LocalErrorCode.AppKeyOrSecretNotProvided,
    "appKey or appSecret not configured in application config file."
    );
    }
    }

    我们把最后抛出异常的语句注释掉即可,然后以Release模式重新编译一下,放到我们的项目的_lib文件夹中并添加引用。接下去就是通过API来获取一些想要的信息了,我这边新建一个SinaWeibo.cs类,作为新浪微博的操作辅助类,下面为构造函数:

     public SinaWeibo(string accessToken,string uid,string sinaWeiboAppKey,string sinaWeiboAppSecret)
    {
    currentUserID = uid;
    OAuthAccessToken oat = new OAuthAccessToken();
    oat.Token = accessToken;
    oat.UserID = uid;
    AMicroblogAPI.Environment.AccessToken = oat;
    if(string.IsNullOrEmpty(AMicroblogAPI.Environment.AppKey))
    AMicroblogAPI.Environment.AppKey = sinaWeiboAppKey;
    if (string.IsNullOrEmpty(AMicroblogAPI.Environment.AppSecret))
    AMicroblogAPI.Environment.AppSecret = sinaWeiboAppSecret;
    }

    当然你也可以不用定义这样的类,直接使用他的API,如果不怕麻烦的话。我们在加载RegisterWithSinaWeiboID.aspx加载时从新浪获取指定用户的信息。再结合用户输入的邮箱就可以创建本站账户了。RegisterWithWeiboID.aspx页面后台代码直接参考RegisterWithWindowsLiveID.aspx即可。

    总结

    整个过程并无难点,细心即可。当然不用这种思路去实现也是完全可以的,但是我认为既然选用了mojoPortal项目,那么就按照作者给我们提供的思路去实现会使得项目更加自然,也便于整体的理解,最重要的是维护方便。今天花了比较多的时间写这么多文字,实属难得,倘若项目时间紧迫,恐怕也要像前几篇文章那样寥寥几句带过。无论如何,哪怕给个别同学带来益处,也是值得的,不是吗?

  • 相关阅读:
    free
    Lynyrd Skynyrd
    Tree 园丁的烦恼
    On Changing Tree
    Path Queries
    Java开发中的23种设计模式详解(转)
    cas单点登录实现
    Java内存溢出详解
    java多线程并发
    java代码实现图片处理功能。对图片质量进行压缩。
  • 原文地址:https://www.cnblogs.com/mike442144/p/2439460.html
Copyright © 2020-2023  润新知