声明演练:为 SharePoint 2010 的受信任登录提供程序创建声明提供程序
**摘要:**了解如何为受信任登录提供程序(SharePoint 信任的外部(即 SharePoint 外部)安全令牌服务 (STS))创建声明提供程序。
上次修改时间: 2013年1月18日
适用范围: Business Connectivity Services | Open XML | SharePoint Designer 2010 | SharePoint Foundation 2010 | SharePoint Online | SharePoint Server 2010 | Visual Studio
本文内容
为受信任登录提供程序创建声明提供程序概述
步骤 1:创建声明提供程序项目
步骤 2:创建存储用户信息并且可用于查询用户声明的 WingtipUserInfo 类
步骤 3:添加用于声明扩充的代码
步骤 4:添加用于搜索声明的代码
步骤 5:添加用于声明解析的代码
步骤 6:向 WingipSTS 注册 WingtipClaimProvider
步骤 7:测试声明提供程序
结论
其他资源
**供稿人:**Andy Li,Microsoft Corporation
目录
为受信任登录提供程序创建声明提供程序概述
步骤 1:创建声明提供程序项目
步骤 2:创建存储用户信息并且可用于查询用户声明的 WingtipUserInfo 类
步骤 3:添加用于声明扩充的代码
步骤 4:添加用于搜索声明的代码
步骤 5:添加用于声明解析的代码
步骤 6:向 WingipSTS 注册 WingtipClaimProvider
步骤 7:测试声明提供程序
结论
其他资源
下载代码:受信任的登录提供程序声明示例(该链接可能指向英文页面)
为受信任登录提供程序创建声明提供程序概述
在声明演练:为 SharePoint 2010 创建受信任的登录提供程序(SAML 登录)中,我们并未为受信任登录提供程序创建声明提供程序。我们要求 Microsoft SharePoint 2010 生成 SPTrustedClaimProvider 对象以从受信任登录提供程序解析、列出和搜索声明。创建和注册 SPTrustedLoginProvider 对象(例如 idClaim.AddKnownClaimValue("user1@wingtip.com"))时,将对可用声明进行硬编码。
在此示例中,我们将为 WingtipSTS 创建自定义声明提供程序。此示例使用内存字符串数组来存储用户和声明信息。实际实现应考虑查询目录服务以在数据库中存储用户信息。
备注
有关声明提供程序的详细信息,请参阅声明提供程序和声明演练:编写 SharePoint 2010 的声明提供程序。
默认情况下,SharePoint 2010 不提供在受信任登录提供程序的人员选取器中搜索和解析。因此,人员选取器会原样返回用户在其中键入的任何内容。这样可能会出现问题,例如,为用户添加了访问权限,但用户仍不具有访问权限。但到目前为止,并无支持搜索和解析的行业标准或协议。即使存在标准或协议,在有些情形下,此功能可能仍不可用。例如,在使用 Windows Live ID 时,出于隐私保护的考虑,有时不允许进行搜索。
此问题的解决方案是自定义声明提供程序。自定义声明提供程序可实现特定协议以支持搜索和解析(如果可用),或者,可只对用户键入的内容执行基本验证以避免错误。例如,如果受信任的登录提供程序用于向 Contoso 用户授予对 Fabrikam 公司网站的访问权限,但 Contoso 没有可用于搜索和解析的协议或服务,则可以使用自定义声明提供程序进行验证,例如验证电子邮件地址是否始终具有后缀"@contoso.com"。
注意在注册期间,声明提供程序的名称必须与受信任登录提供程序的名称相匹配。这是因为,来自受信任登录提供程序的声明的颁发者值是受信任登录提供程序的名称。在选择过程中,如果自定义声明提供程序的名称不同,则该声明提供程序通过人员选取器添加的声明将具有不同的"颁发者"值。因此,授权时将出现不匹配。有关详细信息,请参阅替换 SharePoint 2010 中现成的名称解析 - 第 2 部分(该链接可能指向英文页面)。
更改为受信任登录提供程序分配的声明提供程序非常重要,因为如果不进行更改,除自定义声明提供程序外,还将使用默认声明提供程序,这样会导致混淆。有关更改为受信任登录提供程序分配的声明提供程序的详细信息,请参阅如何替代 SharePoint 2010 中默认的名称解析和声明提供程序(该链接可能指向英文页面)。
本文和演练示例旨在解决有关受信任登录提供程序的搜索和解析问题。此外,用户还可添加自定义声明提供程序以进行扩充,但本文不介绍此内容。在此示例中,让一个声明提供程序解决搜索和解析,让另外一个声明提供程序进行声明扩充(在 CRM 方案中),这是一种有效的配置。
备注
受信任登录提供程序是 SharePoint 信任的外部(即在 SharePoint 外部)安全令牌服务 (STS)。有关声明条款定义的信息,请参阅基于声明的标识术语定义。
SAML 被动登录描述登录过程。在将对 Web 应用程序的登录配置为接受来自受信任登录提供程序的令牌时,此类型的登录即称为 SAML 被动登录。有关详细信息,请参阅传入声明:登录到 SharePoint。
步骤 1:创建声明提供程序项目
打开本文附带的 TrustedLogin 解决方案下载代码。它应包含 3 个项目,如图 1 所示:
TestRPWeb 网站
WingtipSTS 网站
RegisterSTS WinForm 应用程序
图 1. TrustedLogin 解决方案中包含的 3 个项目
在"解决方案资源管理器"中,右键单击 TrustedLogin 解决方案,选择"添加",然后单击"新建项目"。
在"Visual C#"下,选择"空 SharePoint 项目"模板,选择"SharePoint",然后单击"2010"。将 SharePoint 项目命名为 WingtipClaimProvider。然后执行以下操作:
在自定义向导中,选择"场解决方案"。
键入 https://intranet.contoso.com 作为要调试的网站。
在 WingtipClaimProvider 项目中,添加对 Microsoft.IdentityModel.dll 的引用。
有关 Microsoft.IdentityModel.dll 的详细信息,请参阅 Windows Identity Foundation。
右键单击 WingtipClaimProvider 项目,选择"添加",然后单击"新项目"。
将名为 WingtipClaimTypes.cs 的新类文件添加到项目中。
WingtipClaimTypes.cs 文件定义此声明提供程序支持的声明类型。将 WingtipClaimTypes.cs 文件中的代码替换为以下代码。注意,我们另外添加了一个声明类型:department。
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace WingtipClaimProvider { public class WingtipClaimType { public static string EmailAddress = "https://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"; public static string Title = "http://schemas.wingtip.com/sharepoint/2009/08/claims/title"; public static string Department = "http://schemas.wingtip.com/sharepoint/2009/08/claims/department"; } }
步骤 2:创建存储用户信息并且可用于查询用户声明的 WingtipUserInfo 类
在项目中,添加名为 WingtipUserInfo.cs 的新类文件,如图 2 所示。
图 2. 向 WingtipClaimProvider 项目添加新类文件
将 using 语句替换为以下代码。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using Microsoft.SharePoint.Administration; using Microsoft.IdentityModel.Claims; using System.Collections;
将以下两个字符串数组添加到 WingtipUserInfo 类。这两个字符串数组用作用户信息存储。
userDB 字符串数组包含用户信息和关联的声明。(电子邮件地址用作用户的标识符。)
claimsDB 字符串数组包含可供此声明提供程序搜索的可用声明。
private static string[] userDB = { "user1@wingtip.com:Email:user1@wingtip.com", "user2@wingtip.com:Email:user1@wingtip.com", "user3@wingtip.com:Email:user1@wingtip.com", "user1@wingtip.com:Title:Engineer", "user2@wingtip.com:Title:Manager", "user3@wingtip.com:Title:CEO", "user1@wingtip.com:Department:Finance", "user2@wingtip.com:Department:IT", "user3@wingtip.com:Department:AP", }; private static string[] claimsDB = { "Email:user1@wingtip.com", "Email:user2@wingtip.com", "Email:user3@wingtip.com", "Title:Employoee", "Title:Manager", "Title:NorthWest", "Department:Finance", "Department:IT", "Department:AP" };
将以下代码添加到 WingtipUserInfo 类中。这些函数只是从 userDB 和 claimsDB 读取和分析信息的实用工具函数。它们用于解析、搜索和列出声明。
/// <summary> /// A real-world implementation should look up a directory service /// or database to retrieve a user claim. /// The following code is used only for demonstration purposes. /// </summary> /// <param name="username"></param> /// <returns></returns> public static List<Claim> GetClaimsForUser(string username) { List<Claim> userClaims = new List<Claim>(); foreach(string userInfo in userDB) { string[] claims = userInfo.Split(new string[] { ":" }, StringSplitOptions.RemoveEmptyEntries); if (username == claims[0]) { userClaims.Add(new Claim(GetClaimTypeForRole(claims[1]), claims[2], Microsoft.IdentityModel.Claims.ClaimValueTypes.String)); } } return userClaims; } // Manually construct a list of users. // In a real-world production environment, // you should look up from a directory service or database to // retrieve the user information. public static List<string> GetAllUsers() { List<string> allUsers = new List<string>(); // Adding forms-based users. allUsers.Add("user1@wingtip.com"); allUsers.Add("user2@wingtip.com"); allUsers.Add("user3@wingtip.com"); // Adding Windows domain users, if you want this provider to // support Windows claims mode. return allUsers; } /// <summary> /// This function returns all the known claims from the CRM system /// so that the claims provider is able to /// search and resolve the claims in the People Picker. /// </summary> /// <returns></returns> public static Hashtable GetAllClaims() { Hashtable knownClaims = new Hashtable(); foreach(string claimItem in claimsDB) { string[] claim = claimItem.Split(new string[] { ":" }, StringSplitOptions.RemoveEmptyEntries); knownClaims.Add(claim[1].ToLower(), claim[0].ToLower()); } return knownClaims; } public static string GetClaimTypeForRole(string roleName) { if (roleName.Equals("Email", StringComparison.OrdinalIgnoreCase)) return WingtipClaimType.EmailAddress; else if (roleName.Equals("Title", StringComparison.OrdinalIgnoreCase)) return WingtipClaimType.Title; else if (roleName.Equals("Department", StringComparison.OrdinalIgnoreCase)) return WingtipClaimType.Department; else throw new Exception("Claim Type not found!"); }
步骤 3:添加用于声明扩充的代码
添加名为 ClaimProvider.cs 的新类文件。
将 using 语句替换为以下代码。
using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Text; using Microsoft.SharePoint.Administration.Claims; using Microsoft.SharePoint.Administration.Claims; using Microsoft.SharePoint.WebControls; using Microsoft.IdentityModel.Claims;
更改类继承以匹配以下代码。
class ClaimProvider: SPClaimProvider
添加一个构造函数和两个属性。
public ClaimProvider(string displayName) : base(displayName) { } public override string Name { get { return "WingtipClaimProvider"; } } // The AssociatedTrustedLoginProviderName property is used for // generating the SPClaim object. public string AssociatedTrustedLoginProviderName { get { return "WingtipSTS"; } }
添加声明扩充、搜索和解析支持。
/// <summary> /// Must return true if you are doing claims augmentation. /// </summary> public override bool SupportsEntityInformation { get { return true; } } /// <summary> /// Return true if you support claims resolve in the People Picker. /// </summary> public override bool SupportsResolve { get { return true; } } /// <summary> /// Return true if you support claims search in the People Picker. /// </summary> public override bool SupportsSearch { get { return true; } } /// <summary> /// Return true if you support hierarchy display in the People Picker. /// </summary> public override bool SupportsHierarchy { get { return false; } } public override bool SupportsUserSpecificHierarchy { get { return base.SupportsUserSpecificHierarchy; } }
添加以下函数以提供 Claim Types 信息。
注意,在 FillEntityTypes 中,我们同时支持 User 和 FormRoles。必须为支持的每个声明类型返回实体类型。在此示例中,EmailAddress 被视为身份声明 (SPClaimEntityTypes.User),其他两个声明类型被视为角色 (SPClaimEntityTypes.FormRole)。
/// <summary> /// Returns all the claims types that are supported by this provider. /// </summary> /// <param name="claimTypes"></param> protected override void FillClaimTypes(List<string> claimTypes) { if (null == claimTypes) { throw new ArgumentNullException("claimTypes"); } // Add the claim types that will be added by this claims provider. claimTypes.Add(WingtipClaimType.EmailAddress); claimTypes.Add(WingtipClaimType.Title); claimTypes.Add(WingtipClaimType.Department); } /// <summary> /// Return all claim value types that correspond to the claim types. /// You must return the values in the same order as /// in FillClaimTypes(). /// </summary> /// <param name="claimValueTypes"></param> protected override void FillClaimValueTypes(List<string> claimValueTypes) { if (null == claimValueTypes) { throw new ArgumentNullException("claimValueTypes"); } claimValueTypes.Add (Microsoft.IdentityModel.Claims.ClaimValueTypes.String); claimValueTypes.Add (Microsoft.IdentityModel.Claims.ClaimValueTypes.String); claimValueTypes.Add (Microsoft.IdentityModel.Claims.ClaimValueTypes.String); } /// <summary> /// Required for the People Picker. /// Tells the People Picker what information is available /// for the entity. /// </summary> /// <param name="schema"></param> protected override void FillSchema(SPProviderSchema schema) { schema.AddSchemaElement(new SPSchemaElement (PeopleEditorEntityDataKeys.DisplayName, "DisplayName", SPSchemaElementType.TableViewOnly)); } /// <summary> /// Returns the entity type for the claims that are returned from the /// claims provider. /// </summary> /// <param name="entityTypes"></param> protected override void FillEntityTypes(List<string> entityTypes) { entityTypes.Add(SPClaimEntityTypes.User); entityTypes.Add(SPClaimEntityTypes.FormsRole); entityTypes.Add(SPClaimEntityTypes.FormsRole); }
添加以下用于生成声明对象的实用工具函数。
备注
我们明确指定声明的颁发者是 WingtipSTS(而不是 WingtipClaimProvider)。
// The claim from this provider should have WingtipSTS as the // provider name. private SPClaim CreateClaimForSTS(string claimtype, string claimValue) { SPClaim result = new SPClaim(claimtype, claimValue, Microsoft.IdentityModel.Claims.ClaimValueTypes.String, SPOriginalIssuers.Format (SPOriginalIssuerType.TrustedProvider, AssociatedTrustedLoginProviderName)); return result; }
添加 FillClaimsForEntity 函数以支持声明扩充。
/// <summary> /// Implement this method if the provider supports claims augmentation. /// </summary> /// <param name="context"></param> /// <param name="entity"></param> /// <param name="claims"></param> protected override void FillClaimsForEntity(Uri context, SPClaim entity, List<SPClaim> claims) { if (null == entity) { throw new ArgumentNullException("entity"); } if (null == claims) { throw new ArgumentNullException("claims"); } //Adding the role claim. SPClaim userIdClaim = SPClaimProviderManager.DecodeUserIdentifierClaim(entity); //Adding claims for users. List<string> allWingtipUsers = WingtipUserInfo.GetAllUsers(); if (allWingtipUsers.Contains(userIdClaim.Value.ToLower())) { List<Claim> userClaims = WingtipUserInfo.GetClaimsForUser (userIdClaim.Value.ToLower()); foreach (Claim claim in userClaims) { claims.Add(CreateClaimForSTS(claim.ClaimType, claim.Value)); } } }
步骤 4:添加用于搜索声明的代码
添加 FillSearch 方法以支持搜索声明。
注意函数的突出显示部分。当用户搜索电子邮件地址时,我们返回身份声明;否则,返回角色声明。
备注
在此示例中,我们使用 LINQ 查询来支持通配符搜索。
/// <summary> /// Required if you implement the claims search for People Picker. /// </summary> /// <param name="context"></param> /// <param name="entityTypes"></param> /// <param name="searchPattern"></param> /// <param name="hierarchyNodeID"></param> /// <param name="maxCount"></param> /// <param name="searchTree"></param> protected override void FillSearch(Uri context, string[] entityTypes, string searchPattern, string hierarchyNodeID, int maxCount, SPProviderHierarchyTree searchTree) { string keyword = searchPattern.ToLower(); Hashtable knownClaims = WingtipUserInfo.GetAllClaims(); List<string> knownClaimsList = new List<string>(); //Convert the knownClaims.Key into a List<string> for LINQ query. foreach (string claim in knownClaims.Keys) { knownClaimsList.Add(claim); } var claimQuery = knownClaimsList.Where(claim => claim.IndexOf(keyword) >= 0).Select(claim => claim); foreach (string claimValue in claimQuery) { //Get the ClaimType for the claim type. //For example, if you search for "SalesManager", //the ClaimType will be CRMClaimType.Role. string claimType = WingtipUserInfo.GetClaimTypeForRole((string) knownClaims[claimValue]); PickerEntity entity = CreatePickerEntity(); entity.Claim = CreateClaimForSTS(claimType, claimValue); entity.Description = claimValue; entity.DisplayText = claimValue; entity.EntityData[PeopleEditorEntityDataKeys.DisplayName] = claimValue; if (string.Compare(claimType, WingtipClaimType.EmailAddress, true) == 0) { entity.EntityType = SPClaimEntityTypes.User; } else { entity.EntityType = SPClaimEntityTypes.FormsRole; } entity.IsResolved = true; searchTree.AddEntity(entity); } }
步骤 5:添加用于声明解析的代码
添加两个 FillResolve 方法以支持解析声明。
代码会尝试将关键字与 ClaimsDB 中的值相匹配,然后返回相应的数据。
/// <summary> /// Resolve one single claim by using exact match. /// This method is required for both claims search /// and claims resolve. /// </summary> /// <param name="context"></param> /// <param name="entityTypes"></param> /// <param name="resolveInput"></param> /// <param name="resolved"></param> protected override void FillResolve(Uri context, string[] entityTypes, SPClaim resolveInput, List<PickerEntity> resolved) { string keyword = resolveInput.Value.ToLower(); Hashtable knownClaims = WingtipUserInfo.GetAllClaims(); if (knownClaims.ContainsKey(keyword)) { // Get the claim type. // For example, if you search for "SalesManager", the ClaimType // will be CRMClaimType.Role. // In this case, the keyword is the value of the claim. string claimValue = keyword; string claimType = WingtipUserInfo.GetClaimTypeForRole((string)knownClaims[keyword]); PickerEntity entity = CreatePickerEntity(); entity.Claim = CreateClaimForSTS(claimType, claimValue); entity.Description = claimValue; entity.DisplayText = claimValue; entity.EntityData[PeopleEditorEntityDataKeys.DisplayName] = claimValue; if (string.Compare(claimType, WingtipClaimType.EmailAddress, true) == 0) { entity.EntityType = SPClaimEntityTypes.User; } else { entity.EntityType = SPClaimEntityTypes.FormsRole; } entity.IsResolved = true; resolved.Add(entity); } } /// <summary> /// Required if you implement claims resolve for the People Picker. /// </summary> /// <param name="context"></param> /// <param name="entityTypes"></param> /// <param name="resolveInput"></param> /// <param name="resolved"></param> protected override void FillResolve(Uri context, string[] entityTypes, string resolveInput, List<PickerEntity> resolved) { string keyword = resolveInput.ToLower(); Hashtable knownClaims = WingtipUserInfo.GetAllClaims(); List<string> knownClaimsList = new List<string>(); // Convert the knownClaims.Key into a List<string> for LINQ query. foreach (string claim in knownClaims.Keys) { knownClaimsList.Add(claim); } var claimQuery = knownClaimsList.Where(claim => claim.IndexOf(keyword) >= 0).Select(claim => claim); foreach (string claimValue in claimQuery) { // Get the claim type. // For example, if you search for "SalesManager", // the ClaimType will be CRMClaimType.Role. string claimType = WingtipUserInfo.GetClaimTypeForRole((string) knownClaims[claimValue]); PickerEntity entity = CreatePickerEntity(); entity.Claim = CreateClaimForSTS(claimType, claimValue); entity.Description = claimValue; entity.DisplayText = claimValue; entity.EntityData[PeopleEditorEntityDataKeys.DisplayName] = claimValue; if (string.Compare(claimType, WingtipClaimType.EmailAddress, true) == 0) { entity.EntityType = SPClaimEntityTypes.User; } else { entity.EntityType = SPClaimEntityTypes.FormsRole; } entity.IsResolved = true; resolved.Add(entity); } }
添加显示我们不支持层次结构的以下 FillHierarchy 方法。
protected override void FillHierarchy(Uri context, string[] entityTypes, string hierarchyNodeID, int numberOfLevels, SPProviderHierarchyTree hierarchy) { throw new NotImplementedException(); }
编译项目并更正任何错误。
步骤 6:向 WingipSTS 注册 WingtipClaimProvider
在注册期间,声明提供程序的名称必须与受信任登录提供程序的名称相匹配。这是因为,来自受信任登录提供程序的声明的颁发者值将是该受信任登录提供程序的名称。在选择过程中,如果自定义声明提供程序的名称不同,则该声明提供程序通过人员选取器添加的声明将具有不同的 issuer 值。因此,授权时将出现不匹配。有关详细信息,请参阅替换 SharePoint 2010 中现成的名称解析 - 第 2 部分(该链接可能指向英文页面)。
在"解决方案资源管理器"中,右键单击"功能"节点,然后单击"添加新功能"。
将功能的"范围"更改为 Farm。
右键单击"Feature1",然后单击"添加事件接收器"。
将 using 语句替换为以下代码。
using System; using System.Runtime.InteropServices; using System.Security.Permissions; using Microsoft.SharePoint; using Microsoft.SharePoint.Security; using Microsoft.SharePoint.Administration.Claims;
更改类继承以匹配以下代码。
public class Feature1EventReceiver :SPClaimProviderFeatureReceiver
将以下代码添加到类中。将其他代码保留为注释。
private string providerDisplayName = "Wingtip Claim Provider"; private string providerDescription = "Provides Claims from Wingtip"; public override string ClaimProviderAssembly { get { return typeof (WingtipClaimProvider.ClaimProvider).Assembly.FullName; } } public override string ClaimProviderDisplayName { get { return providerDisplayName; } } public override string ClaimProviderType { get { return typeof(WingtipClaimProvider.ClaimProvider).FullName; } } public override string ClaimProviderDescription { get { return providerDescription; } } public override bool ClaimProviderUsedByDefault { get { return true; } }
编译 WingtipClaimProvider 项目并确保它成功生成。
右键单击 WingtipClaimProvider 项目,然后单击"部署"。此步骤会向服务器场注册声明提供程序。
在"RegisterSTS"项目中打开 Form1。
添加名为 Update ClaimProvider 的按钮。
服务器场中应只有两个按钮:一个是 Register WingtipSTS,另一个是 Update ClaimProvider,如图 3 所示。
图 3. 显示"Update ClaimProvider"按钮的 Form1
在新按钮的隐藏代码中,添加以下代码。
SPSecurityTokenServiceManager manager = SPSecurityTokenServiceManager.Local; string providerName = "WingtipSTS"; SPTrustedLoginProvider provider = manager.TrustedLoginProviders[providerName]; provider.ClaimProviderName = "WingtipClaimProvider"; provider.Update(); }
编译应用程序并更正任何错误。
右键单击"RegisterSTS"项目,依次选择"调试"和"启动新实例"。
应用程序启动后,单击"Update ClaimProvider"按钮。这会更新 WingtipSTS 受信任登录提供程序的声明提供程序。
步骤 7:测试声明提供程序
同样要确保 WingtipSTS 项目正在运行,并且可通过浏览器访问。
启动管理中心网站。
在"创建网站集"页(参见图 4)上,选择 https://intranet.contoso.com。
图 4."创建网站集"页
在"网站集管理员"部分,单击"浏览"图标以启动"人员选取器"。注意,左侧有一个"Wingtip 声明提供程序",如图 5 所示。它是刚创建的声明提供程序。
图 5. 人员选取器中显示的 Wingtip 声明提供程序
在左侧窗格中,选择"Wingtip 声明提供程序"。在"搜索"框中键入 user。应返回三个用户,如图 6 所示。
图 6. 搜索"user"时在人员选取器中返回三个用户
选择"User1@wingtip.com"作为网站集管理员。
在 https://intranet.contoso.com/sites/Test1 下创建网站集。
创建网站集后,请在浏览器中导航至 https://intranet.contoso.com/sites/Test1。
在 WingtipSTS 登录页上,键入 user1@wingtip.com 的凭据(密码可以为任何内容),如图 7 所示。
备注
确保正在运行 WingtipSTS。如果它未运行,请右键单击 WingtipSTS 项目,然后选择"在浏览器中查看"。
图 7. WingtipSTS 登录页
单击"提交"。您应重定向回 SharePoint 网站。(首次启动时可能需要几分钟。)
图 8. 成功登录后重定向到 SharePoint 网站
在"网站操作"菜单上,选择"网站权限"。
在功能区上,单击"授予权限"。
键入 IT,然后按 Enter。解析名称后,单击 IT,然后选择"it [Wingtip 声明提供程序]",如图 9 所示。
图 9. 选择"it [Wingtip 声明提供程序]"
单击"浏览"图标以打开"人员选取器"对话框。
搜索 AP。选择从 Wingtip 声明提供程序返回的项,如图 10 所示。
图 10. 从 Wingtip 声明提供程序选择"AP"
将 IT 和 AP 添加到 Members 组(参与者),如图 11 所示。
图 11. 将"IT"和"AP"添加到 Members 组(参与者)
注销 user1@wingtip.com(如图 12 所示),然后关闭浏览器的所有实例。
备注
这一步非常重要。请确保关闭了浏览器的所有实例。
图 12. 注销
打开 Internet Explorer 或其他浏览器的新实例,然后转到 https://intranet.contoso.com/sites/Test1。
尝试使用 user2@wingtip.com 登录。
能登录吗?为什么能或为什么不能?
尝试使用 user3@wingtip.com 登录。
能登录吗?为什么能或为什么不能?
创建声明查看器 Web 部件,然后将其添加到主页并显示所有 3 个用户的声明。(未提供此步骤的代码。)
结论
在本演练中,您学习了如何为受信任登录提供程序创建声明提供程序。受信任登录提供程序是 SharePoint 信任的外部 STS。
其他资源
有关详细信息,请参阅以下资源: