每周源代码25——OpenID版

[原文发表地址]  The Weekly Source Code 25 - OpenID Edition

[原文发表时间] 2008-04-30 7:11 AM

我在Corillian(我的上一份工作)花了很多时间琢磨Identity. 在离开的前几个月,我开始着手研究Cardspace 和 OpenID。这都是一年前的事了。我们还制作一个关于OpenID的播客openid_3

当时,在最初是由Grant Monroe 用Boo编写OpenID的时候,我试图先只采取.NET来实现。然后再将其移植到C#中,这使我经历了痛苦的几个编程阶段Andrew ArnottJason Alexander充满激情,为此,我们数个晚上都工作到深夜,试图开发一个非常棒的OpenID库。最后,我放弃了,但他俩却迎难而上,创建了dotnetopenid下载),其中包括一个客户端、服务器和Andrew开发的非常棒的ASP.NET控件。

时间飞逝啊!再看看现在,我的新朋友Aaron Hockley决定支持并推广OpenID。他说到:

“从现在开始,如果留言板不支持OpenID,我将不会再评论科技博客。”

他就是这样一个人,但不可否认,他是个好心人, 他指出:

“谷歌把它作为一个Blogger选项。它被用作为一个超级易于安装的WordPress插件Movable Type将其作为内置功能

OpenID 是一项不断发展的好技术。你可能已经有一个OpenID了,例如,你有一个Yahoo!帐户,接着你可以在更多的地方使用到这个帐号。

怎样将你的博客转换成一个OpenID呢?

Simon Willison 写了一篇《关于如何将你的博客转换成OpenID》的文章,内容其实很简单。

步骤一:获得一个OpenID。有大量的服务器和服务可以使用。我使用https://www.myopenid.com 的原因有两个。第一,我认识该网站的CEO(他们在波特兰);第二,他们支持有选择性地使用CardSpace进行身份验证(和密码验证的标准方法差不多)。

步骤二: 将这两行添加到您博客的主要模板顶部的<HEAD></HEAD>标签之间。几乎所有的博格引擎都支持模板编辑,所以这应该非常简单,可行性强。

例如:

    1: <link rel="openid.server" href="https://www.myopenid.com/server" /> 
    2: <linkrel="openid.delegate" href=https://YOURUSERNAME.myopenid.com/ /> 

这样,就可将您的域名/博客 作为OpenID。 现在,当我登陆https://www.hanselman.com时,就可以看到OpenID登录选项了。你也可以的!现在就试试吧!

让OpenID登录更简单

如果你有一个博客或网站支持OpenID,你应该可以获取这个小的JavaScript代码段,并从 https://www.idselector.com/ 上安装一个OpenID ID选择器到你的博客上。

clip_image002

减缓使用OpenID技术的一个原因是:很多人不知道自己原本就有一个OpenID。这就是这个小小的Javascript代码段正尝试去做的事,通过向大家展示大家所熟识的网站。通过此方法,我爸爸也可以通过Yahoo来登陆,这给他带来了帮助。虽然有点小麻烦,但这是个不错的开端。我添加了https://www.idselector.com/ 到我的博客中以供大家评论。

对DasBlog添加OpenID支持

一年前,我原本打算将Boo代码移植到C#中,以使OpenID 能在DasBlog上使用,但最终还是放弃了。然而,昨晚,我又重新熟悉了 OpenID 特性(它现在是2.0版本了),并开始阅读https://code.google.com/p/dotnetopenid/源代码。

总之,蛮有乐趣的。我能在两小时内使OpenID正常运行起来,并在另外两个博客上也起作用。我不得不对Andrew ArnottJason Alexander和他们整个团队所做的令人难以置信的工作表示赞赏。话说回来,亲爱的读者,你应该知道:

我在DasBlog(如果你不清楚,我再说一遍,它是运行于此网站或其他网站的基于C#和XML的博客)上有两种方案。

首先,我想让留言板支持OpenID。而且它并会在FormsAuthentication上呈现“以用户登入”状态。我认为这不是一个常用方案,我把它描述为“一次性临时身份验证”,在这个例子中,我在一个中等复杂的方案下直接使用了dotnetopenid类。

其次, 我想支持OpenID作为管理员身份来登录我的网站。事实上,这将通过FormsAuthentication登录。 你可能会关心这个通常的方案,因为它非常典型的。在这个例子中,我使用dotnetopenid ASP.NET控件,它和取消登陆一样简单 (这是很容易的) 。

这里是第一个比较难的方案

如果您输入您的OpenID,并点击Submit Comment,那么我们将保存当前条目及您提交的评论。我们将再次要求去获得验证。返回的时候还要用到它们。如果你在WebFarm上运行,你要将这些临时变量存储在没有node-affinit的数据库或某个地方。

    1: Session["pendingComment"] = comment.Text;
    2: Session["pendingEntryId"] = ViewState["entryId"] as string;
    3: OpenIdRelyingParty openid = new OpenIdRelyingParty();
    4: IAuthenticationRequest req = openid.CreateRequest(openid_identifier.Text);
    5: ClaimsRequest fetch = new ClaimsRequest();
    6: fetch.Email = DemandLevel.Require;
    7: fetch.Nickname = DemandLevel.Require;
    8: req.AddExtension(fetch);SaveCookies();
    9: req.RedirectToProvider();
   10: return;

 

据OpenID人士所称,我所认为的“OpenID客户端” 其实被称作”Relying Party”或简称为 “RP”。在此代码中,我们创建了一个AuthenticationRequest并添加一些额外的声明。 在这个低级别的库中有一个友好的基于接口的扩展模型。它使得您可以从用户的个人资料信息中Request或Require信息。 在博客的评论中,我只需要您的Gravatar电子邮件,并显示您的昵称。

然后,调用RedirectToProvider,这是请求方应该做的。记得我前面讲过这是个很难的方案!其实也没那么难。;)

下一步,我们重新转向一个OpenIDProvider,我们进行身份验证(不验证也可以),然后和在GET上编码的其他信息一起传回。在返回的过程中,在Page_Load(或HttpHandler)检查响应状态。 如果验证完毕,我们攫取要求的信息并添加注释。Bam. Sprinkle处理一个小错误,然后我们就全部就绪了。

    1: OpenIdRelyingParty openid = new OpenIdRelyingParty();
    2: if (openid.Response != null)
    3: {         // Stage 3: OpenID Provider sending assertion response
    4:    switch (openid.Response.Status)
    5:    {
    6:       case AuthenticationStatus.Authenticated:
    7:          ClaimsResponse fetch = openid.Response.GetExtension(typeof(ClaimsResponse)) as ClaimsResponse;
    8:          string nick = fetch.Nickname;
    9:          string homepage = openid.Response.ClaimedIdentifier;
   10:          string email = fetch.Email;
   11:          string comment = Session["pendingComment"] as string;
   12:          string entryId = Session["pendingEntryId"] as string;
   13:          if (String.IsNullOrEmpty(comment) == false && String.IsNullOrEmpty(entryId) == false)
   14:          {
   15:             AddNewComment(nick, email, homepage, comment, entryId, true);
   16:          }
   17:          break;
   18:    }
   19: } 

下面是第二种方案,我们将以博客管理员身份登陆。我只需在ASPX页面注册一个DotNetOpenId组件,并将<openidlogin>控件置于页面上就行了。请注意,甚至我在上面的手动的情况下创建的声明也仅仅是此控件的属性。还有些像OnLoggedIn的事件可以处理结果。

    1: <%@ Register Assembly="DotNetOpenId" Namespace="DotNetOpenId.RelyingParty" TagPrefix="cc1" %>
    2: <cc1:openidlogin id="OpenIdLogin1" <br cssclass="openidLogin" runat="server">RequestEmail="Require" RequestNickname="Request" RegisterVisible="false"
    3:  RememberMeVisible="True" PolicyUrl="~/PrivacyPolicy.aspx" TabIndex="1"
    4:  OnLoggedIn="OpenIdLogin1_LoggedIn"/></cc1:openidlogin>

下面的截图很好地呈现了该控件。

image

在OnLoggedIn事件中,我调用现有安全APIs(多亏了Tony BunceAnthony Bouch),并在FormsAuthentication上设置了AuthCookie.

    1: protected void OpenIdLogin1_LoggedIn(object sender, OpenIdEventArgs e)
    2: { 
    3:   UserToken token = SiteSecurity.Login(e.Response);
    4:    if (token != null)
    5:    {
    6:        FormsAuthentication.SetAuthCookie(userName, rememberCheckbox.Checked);
    7:        Response.Redirect(SiteUtilities.GetAdminPageUrl(), true);
    8:    }
    9: } 

喔哟,我喜欢使用精心设计的库。在此时,剩下要做的就是添加一些CSS,并进行整理。

OpenID , ASP.NET WebForms 以及 MVC

dotnetopenid 源包括样本网站的资源。它实际上包括三个样本,两个WebForm以及一个ASP.NET MVC。

MVC的执行是

    1: public void Authenticate() {
    2:     var openid = new OpenIdRelyingParty();
    3:   if (openid.Response == null) {
    4:       // Stage 2: user submitting Identifier
    5:       openid.CreateRequest(Request.Form["openid_identifier"]).RedirectToProvider();
    6:    } else {
    7:         // Stage 3: OpenID Provider sending assertion response
    8:       switch (openid.Response.Status) {
    9:            case AuthenticationStatus.Authenticated:
   10:                 FormsAuthentication.RedirectFromLoginPage(openid.Response.ClaimedIdentifier, false);
   11:                 break;
   12:           case AuthenticationStatus.Canceled:
   13:              ViewData["Message"] = "Canceled at provider";
   14:                RenderView("Login");
   15:                 break;
   16:           case AuthenticationStatus.Failed:
   17:                ViewData["Message"] = openid.Response.Exception.Message;
   18:                 RenderView("Login");
   19:                 break;
   20:       }
   21:    }
   22: }

CardSpace怎么样呢?

 OpenID是一个规范的协议:“免去了在不同网站使用不同帐号的麻烦,简化您的在线体验。” 最酷的是它具有开放性,你(用户)可以任意选择提供方。所以,要么搞砸,要么成功,我们自己说了算。Infocard Logo

如果你将NET 3.0放在系统上的话,CardSpace是内置于Vista和XP系统中的。 里面也有针对Safari Firefox的Identity Selectors。它跟OpenID的不同之处在于,它与强身份验证有关。 因此,他们是互补的。

这里是我的CardSpace登录界面,我准备登录到这个博客... ...

image

因为我选择的OpenID 提供商 是https://www.myopenid.com(免费的),也支持InfoCard和SSL证书认证以及强度密码。

请注意下面 IconCard紫色图标旁边的“Sign into Information Card”图标。

image

一个OpenID供应商可以选择使用任何可用的东西对您进行验证。这里有一个 比利时人使用EDI 通过一个OpenID提供商进行身份验证的视频,这个OpenID提供商是https://openid.trustbearer.com/,它支持生物识别设备,USB钥匙和智能卡。

那么,该怎么做呢

参与进来试试吧!你可以按照下列步骤操作。

     在 MyOpenID或在许多公共OpenID 提供商中注册一个免费的OpenID。

    在其中某个支持OpenID的网站中使用您的新OpenID。

  •  再回到这个帖子处, 使用OpenID来发布你的第一条评论。

    观看SimonWillison 谈论关于OpenID的案例视频

如果你是开发人员,获取一个诸如dotnetopenidOpenID库,并考虑在你的应用程序中使用它。同时考虑使用Javascript ID Selector来创造一个更好的用户体验。