基于声明的身份验证和 WIF:第 2 部分
本部分主要讨论 WIF 并逐步演示一个示例
引言
这篇文章是关于我关于基于声明的身份验证的帖子的第二部分。大家可以从这里访问我的第一篇文章。
在我上一篇文章中,我讨论了当今身份验证实现的问题、基于声明的身份验证的详细信息以及基于声明的身份验证的基本组件。现在在这篇文章中,我将通过一个示例,逐一讨论 Windows Identity Foundation 和主要概念。
什么是 Windows Identity Foundation (WIF)
首先,我想说 Windows Identity Foundation 是 微软利用基于声明的身份验证的方式。让我们看看 MSDN 的定义。
Windows Identity Foundation 使 .NET 开发人员能够将身份逻辑从其应用程序中外部化,从而提高开发人员的工作效率、增强应用程序安全性并实现互操作性。享受更高的生产力,将相同的工具和编程模型应用于构建本地软件和云服务。通过减少自定义实现并使用基于声明的单一简化身份模型来创建更安全的应用程序。通过基于行业标准协议的互操作性,实现应用程序部署的更大灵活性,允许应用程序和身份基础设施服务通过声明进行通信。
所以我们可以说,Windows Identity Foundation 提供了一组类,这些类有助于实现基于声明的身份验证。
必备组件
要使用 WIF,您需要 Windows 2003 Server+ 或 Windows 7/8/Vista。
WIF SDK 提供了一些 Visual Studio 模板,有助于开发声明感知应用程序。这些模板是
- ASP.NET 安全令牌服务网站
- 声明感知 ASP.NET 网站
- 声明感知 WCF 服务
- WCF 安全令牌服务
以上模板可在文件菜单下的新建网站中找到。
让我们讨论一个例子
所以今天,我们将创建一个 ASP.NET 应用程序(依赖方应用程序 - RP)。此外,我们还将创建一个自定义身份提供程序,并使用此身份提供程序进行用户身份验证。
以下是我们需要执行的主要步骤
- 创建自定义身份提供程序
- 创建 ASP.NET 应用程序
- 在身份提供程序和 ASP.NET 应用程序之间创建信任
所以我们首先创建一个身份提供程序。
创建自定义身份提供程序
所以在这里,我将一步一步地创建自定义身份提供程序。
打开 Visual Studio -> 创建新网站 -> 选择 ASP.NET 安全令牌服务网站(我已选择 HTTP 位置直接将其托管在 IIS 上。)

现在您的示例身份提供程序已创建。它为您提供了基本的基础设施。它包含一个实际验证用户的登录页面,此处使用了表单身份验证。
创建 ASP.NET 应用程序
我已创建如下 ASP.NET 应用程序

现在,由于这已经创建了一个内置的身份验证模块。您可以将其全部删除,因为我们不会使用它。或者您可以创建一个空的 ASP.NET 解决方案和一些页面,根据您的要求。为了演示,我已删除了帐户文件夹。
在身份提供程序和 ASP.NET 应用程序 (RP) 之间创建信任
这可以使用 WIF SDK 提供的 FedUtil 完成。此外,从 UI,我们可以在 ASP.NET 网站中添加 STS 引用,并在身份提供程序和依赖方之间建立信任关系。请看以下步骤以添加引用。
- 向 ASP.NET 网站添加 STS 引用。

- 这是 FedUtil 的第一个屏幕,显示 ASP.NET 网站 (RP) 的 URI 和位置

- 如果您没有在 SSL 上托管您的 ASP.NET 网站 (RP),它将显示以下警告。在生产环境中,身份提供程序和 ASP.NET 网站 (RP) 之间的所有通信都应仅通过 SSL 进行。此处出于演示目的,我没有使用 SSL。我点击了“是”。

- 在此屏幕中,它要求选择 STS(安全令牌服务)。并有三个选项。由于我们已经创建了 STS,我们需要选择选项“使用现有的 STS”。

为了建立信任关系,我们需要提供身份提供程序提供的联合元数据。
- 现在我们需要浏览我们创建的 STS 的 `FederationMetada` XML 文件。

`FederationMetadata` 文件位于 `STSWebsite` 物理文件夹下的特殊文件夹层次结构“FederationMetadata/2007-06”中。
- 并选择 `FederationMetdata`。然后点击下一步。

- 同样,由于我的 STS 未托管在 SSL 上,因此显示以下警告消息。我只是点击了“是”。

- 这里询问是否要加密令牌。在生产环境中应该加密。这里我选择了“不加密”选项用于演示。

- 现在它显示了 STS 传递给 RP 的所有声明。我们可以根据需要从 STS 传递更多声明给 RP。在添加 STS 引用时,所有声明都会在此处显示。默认情况下,STS 只提供了两个角色(姓名和角色)。

- 这是摘要屏幕,显示了 STS 和 RP 的详细信息。需要查看并点击完成。

注意:这里有一个定期更新联合元数据的选项。如果 STS 正在发生更改,例如令牌或声明等,就需要知道。RP 只有在 `federationmetadata` 更新时才会知道,否则,如果有人删除了一个声明但元数据没有更新,它将允许获取该声明,但实际上在运行时您将不会获得该声明,这不是一个好的情况。应该始终保持元数据为更新形式。
点击完成。一个名为 FederationMetadata 的文件夹已添加到 ASP.NET 网站(依赖方 - RP)中,如下所示

让我们运行应用程序。
现在,如果您运行应用程序,它将抛出一个异常,显示“无法评估表达式,因为代码已优化或本机框架在调用堆栈顶部。”
这是一个问题,我已经为此写了一篇小文章。您可以轻松解决它。请查看此处 [^]。
现在,修改后,它将顺利运行,并将您带到由 STS 提供的登录页面。这是 STS 提供的默认登录页面,在这里您无需输入密码,只需输入一个名称并点击登录,如下所示

它将重定向到 STS 的另一个页面,该页面将实际启动创建令牌和声明的过程。创建后,它将以经过身份验证的用户的身份传输到您的网站。
现在我们的应用程序正在运行。正如 STS 中,我们有一个使用表单身份验证并默认对每个用户进行身份验证的示例登录页面。在这里我们可以放置我们的代码,无论我们是想使用 Windows 身份验证/表单身份验证来对用户进行身份验证,并使用数据库,我们都可以,而且我们还可以从任何存储(例如数据库)获取用户的一些数据,并根据我们的要求通过声明发送这些数据。
所以现在我将展示如何向用户的声明中传递更多信息。这样就可以在这里获得额外的声明。当您创建 STS 时,在 App_Code 文件夹中会添加四个文件。其中一个名为 CustomSecurityTokenService.cs。在这个文件中,有一个方法 `GetOutputClaimsIdentity`,它实际上创建了声明。我们需要在这里添加声明(我添加了一些)
/// <summary>
/// This method returns the claims to be issued in the token.
/// </summary>
/// <param name="principal">The caller's principal.
/// <param name="request">The incoming RST, can be used to obtain additional information.
/// <param name="scope">The scope information corresponding to this request.
/// <exception cref="ArgumentNullException">If 'principal' parameter is null.</exception>
/// <returns>The outgoing claimsIdentity to be included in the issued token.</returns>
protected override IClaimsIdentity GetOutputClaimsIdentity
( IClaimsPrincipal principal, RequestSecurityToken request, Scope scope )
{
if ( null == principal )
{
throw new ArgumentNullException( "principal" );
}
IClaimsIdentity claimsIdentity = (IClaimsIdentity)principal.Identities[0];
ClaimsIdentity outputIdentity = new ClaimsIdentity();
// Issue custom claims.
// Update the application's configuration file too to reflect new claims requirement.
outputIdentity.Claims.Add( new Claim
( System.IdentityModel.Claims.ClaimTypes.Name, principal.Identity.Name ) );
outputIdentity.Claims.Add(new Claim(ClaimTypes.Role, "Manager"));
//I added these custom claims
outputIdentity.Claims.Add(new Claim(ClaimTypes.Email, "brij@gmail.com"));
outputIdentity.Claims.Add(new Claim(ClaimTypes.Gender, "Male"));
return outputIdentity;
}
我添加了两个声明(`Email`、`Gender`),如上所示。这些声明将在 ASP.NET 网站(依赖方)中可用。
同一个身份提供程序可以在多个应用程序中使用。
我希望以上示例能有很大帮助。在本系列的下一篇文章中,我将讨论另一种实现基于声明身份验证的技术,这种技术被广泛称为身份联合。