3

我正在创建一个网站 .NET,它将为其用户提供特定服务。让我们称之为 service1.com。将来会有service2.com,他们将共享数据库。我还想通过提供使用 Google、Facebook、Twitter + 自定义注册的登录来进行用户友好的身份验证,以防用户没有使用 Google 等,以便他们可以注册。我将使用DotNetOpenAuth库。所以场景类似于SO。

现在谷歌有直接的问题:它为不同的领域提供了不同的声明标识符——这意味着我不能将它用作用户的 ID,但必须将电子邮件添加到图片中以解析用户(就像 SO 正在做的那样)。

除此之外,这意味着我必须支持 Facebook Connect、Twitter 以及每个服务站点上的每个附加登录选项。

所以我想出了 OpenID 代理的想法:

  • 我使用自己的独立数据库创建 OpenID 提供程序 openid.service.com
  • service1.com 和 service2.com 是其依赖方并共享自己的数据库
  • openid.service.com 可以通过各种不同的方式对用户进行身份验证:
    • 使用 openid.service.com 的新帐户(基本注册,如 SO
    • OpenID(Gmail、Yahoo、...)
    • 脸书连接
    • 推特
    • ...
  • 登录选项和注册表单将显示在每个服务网站的 iframe 中(就像 SO 注册一样)
  • 一旦 openid.service.com 通过任何选项对用户进行身份验证,它就会向依赖方回调提供声明的标识符

所以最终结果看起来像这样:在此处输入图像描述

优点:

  • 服务可以使用 openid.service.com 提供的声明标识符来识别正在登录的用户
  • 服务可以简单地添加到所需的域
  • 添加更多登录选项是微不足道的,因为 openid.service.com 处理它
  • 谷歌声称标识符不会改变,因为 openid.service.com 处理身份验证

缺点:

  • 身份验证链更长(服务不直接通过 Google 进行身份验证等)
  • ???

这是实现这样一个系统的一种不错的方式吗?这是否还有其他缺点?

4

1 回答 1

2

是的,这是解决这个问题的合理方法。事实上,我认为StackOverflow 做同样的事情。不使用 OpenID 的人的自定义用户数据库也位于 openid.service.com,因此实际上在这种情况下他们也会使用 OpenID,尽管他们不知道。

需要注意的一件事是,您的示例中的 openid.service.com 将无法断言来自 Google 和其他人的原始声明标识符,因为辅助 RP 不会接受来自您的中介的声明,因为它对那些声明的 ID 没有权限. 相反,您可以做的是openid.service.com 和每个辅助 RP 之间的无身份验证OpenID。是的,OpenID 实际上有一个流程,其中没有声称的标识符从 OP 传递到 RP——只有扩展。因此,您可以使用 DotNetOpenAuthFetchRequestFetchResponse扩展在辅助 RP 和中央服务之间请求用户的实际 claim_id。辅助RP必须非常小心只接受来自您的中央 RP 的断言。

这是辅助 RP 和中央 RP 之间的代码草图:

第 1 步:RP 向 openid.service.com 请求用户身份验证

OpenIdRelyingParty rp;
var request = rp.CreateRequest("https://openid.service.com/");
request.IsExtensionOnly = true;
var fetchRequest = new FetchRequest();
fetchRequest.Attributes.AddRequired("http://openid.service.com/useridentity");
request.AddExtension(fetchRequest);
request.RedirectToProvider();

第 2 步:openid.service.com,作为 OP,接收请求(作为一个 OP 是一个巨大的责任......这是一个非常不完整的示例。您应该参考可用的 OpenIdProvider 示例。)

OpenIdProvider op;
IRequest request = op.GetRequest();
/// ...
IAnonymousRequest anonRequest = request as IAnonymousRequest;
if (anonRequest != null) {
    // The key part for this sample snippet is that you make sure the RP asking
    // is one of your own, since you're not following the typical OpenID flow.
    if (!IsWhiteListedRealm(hostRequest.Realm)) {
        anonRequest.IsApproved = false; // reject all RPs that aren't in the whitelist
    } else {
        // Perhaps here is where you'll start your double role as an RP
        // to authenticate the user if there isn't already a FormsAuth cookie.
    }
}

return op.PrepareResponse(request).AsActionResult()

第 3 步:辅助 RP 接收来自您的代理 OpenID 服务的响应。

OpenIdRelyingParty rp;
var response = rp.GetResponse();
if (response != null) {
    if (response.Provider.Uri.Authority != "openid.service.com") {
        throw new Exception(); // only assertions from our own OP are trusted.
    }

    if (response.Status == AuthenticationStatus.ExtensionsOnly) {
        var fetchResponse = response.GetExtension<FetchResponse>();
        string claimedId = fetchResponse.GetAttributeValue("http://openid.service.com/useridentity");
        FormsAuthentication.RedirectFromLoginPage(claimedId);
    }
}

这些样本并不完整。并且上述内容不适用于担任这些角色的网站的许多正常实践安全缓解措施。这只是一个草图,概述了您的应用程序在特定情况下应采取的一些额外步骤。

于 2013-03-24T14:03:54.477 回答