首页 文章

OpenID提供程序作为身份验证代理

提问于
浏览
3

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

现在Google立即出现问题:它提供different claimed identifier for different realm - 这意味着我不能将其用作用户ID,但必须在图片中添加电子邮件以解析用户(like SO is doing) .

除此之外,这意味着我必须支持Facebook Connect,Twitter以及每个服务站点上的所有其他登录选项 .

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

  • 我使用自己独立的数据库创建OpenID提供程序openid.service.com

  • service1.com和service2.com是其依赖方并共享自己的数据库

  • openid.service.com可以通过各种不同的方式验证用户:

  • 与openid.service.com的新帐户(basic sign up like SO

  • OpenID(Gmail,Yahoo,...)

  • Facebook Connect

  • 推特

  • ......

  • 登录选项和注册表单将显示在每个服务网站的iframe中(如SO注册)

  • 一旦openid.service.com通过任何选项对用户进行身份验证,它为依赖方回调提供了声明的标识符

所以最终结果看起来像这样:
enter image description here

PROS:

  • 服务可以使用openid.service.com提供的声明标识符来标识登录的用户

  • 服务可以简单地添加到所需的域

  • 添加更多登录选项是微不足道的,因为openid.service.com处理它

  • Google声称标识符不会更改,因为openid.service.com会处理身份验证

CONS:

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

  • ???

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

1 回答

  • 2

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

    需要注意的一点是,您的示例中的openid.service.com将无法断言Google和其他人的原始声明标识符,因为辅助RP不会接受您的中间人的断言,因为它对这些声明的ID没有权限 . 相反,你可以做的是openid.service.com和你的每个辅助RP之间的无身份验证OpenID . 是的,OpenID实际上有一个流程,其中没有声明的标识符从OP传递到RP - 仅扩展 . 因此,您可以使用DotNetOpenAuth FetchRequestFetchResponse 扩展来请求用户在您的辅助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 samples that are available . )

    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);
        }
    }
    

    这些样本是 not complete . 并且上述内容不适用于填充这些角色的网站的许多常规安全缓解措施 . 这仅仅是一个草图,概述了您的应用程序在您的特定情况下应采取的一些额外步骤 .

相关问题