在 Windows Server 中为 AD FS 生成自定义身份验证方法
本演练讲解如何在 Windows Server 2012 R2 中为 AD FS 实现自定义身份验证方法。 有关详细信息,请参阅其他身份验证方法。
警告
可在此处构建的示例仅用于教育目的。 这些说明适用于可公开所需模型元素的最简单、最少量的实现。 没有身份验证后端、错误处理或配置数据。
设置开发工具箱
本演练使用 Visual Studio 2012。 可使用能为 Windows 创建 .NET 类的任何开发环境生成项目。 项目必须面向 .NET 4.5,因为 BeginAuthentication 和 TryEndAuthentication 方法使用 System.Security.Claims.Claim 类型(.NET Framework 版本 4.5 的一部分)。 项目需要一个引用:
引用 dll | 所在位置 | 要求 |
---|---|---|
Microsoft.IdentityServer.Web.dll | dll 位于已安装 AD FS 的 Windows Server 2012 R2 服务器上的 %windir%\ADFS 中。 必须将此 dll 复制到开发计算机并在项目中创建显式引用。 |
接口类型,包括 IAuthenticationContext、IProofData |
创建提供程序
在 Visual Studio 2012 中,选择“文件”->“新建”->“项目...”
选择“类库”并确保面向 .NET 4.5。
在已安装 AD FS 的 Windows Server 2012 R2 服务器上复制 %windir%\ADFS 中的 Microsoft.IdentityServer.Web.dll,并将其粘贴到开发计算机上的项目文件夹中。
在解决方案资源管理器中,右键单击“引用”,然后选择“添加引用…”
浏览到 Microsoft.IdentityServer.Web.dll 的本地副本,然后选择“添加...”
单击“确定”以确认新引用:
现在应设置为解析提供程序需要的所有类型。
向项目添加一个新类(右键单击你的项目,依次选择“添加...”和“类...”,然后为其命名(如 MyAdapter),如下所示:
在新文件 MyAdapter.cs 中,将现有代码替换为以下内容:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Globalization; using System.IO; using System.Net; using System.Xml.Serialization; using Microsoft.IdentityServer.Web.Authentication.External; using Claim = System.Security.Claims.Claim; namespace MFAadapter { class MyAdapter : IAuthenticationAdapter { public IAuthenticationAdapterMetadata Metadata { //get { return new <instance of IAuthenticationAdapterMetadata derived class>; } } public IAdapterPresentation BeginAuthentication(Claim identityClaim, HttpListenerRequest request, IAuthenticationContext authContext) { //return new instance of IAdapterPresentationForm derived class } public bool IsAvailableForUser(Claim identityClaim, IAuthenticationContext authContext) { return true; //its all available for now } public void OnAuthenticationPipelineLoad(IAuthenticationMethodConfigData configData) { //this is where AD FS passes us the config data, if such data was supplied at registration of the adapter } public void OnAuthenticationPipelineUnload() { } public IAdapterPresentation OnError(HttpListenerRequest request, ExternalAuthenticationException ex) { //return new instance of IAdapterPresentationForm derived class } public IAdapterPresentation TryEndAuthentication(IAuthenticationContext authContext, IProofData proofData, HttpListenerRequest request, out Claim[] outgoingClaims) { //return new instance of IAdapterPresentationForm derived class } } }
我们尚未准备好进行生成...还有两个接口要处理。
另外向项目添加两个类:一个用于元数据,另一个用于表示形式。 可在上述类所在的同一文件中添加这些内容。
class MyMetadata : IAuthenticationAdapterMetadata { } class MyPresentationForm : IAdapterPresentationForm { }
接下来,可以为每个项添加所需的成员。首先,添加元数据(附上有用的内联注释)
class MyMetadata : IAuthenticationAdapterMetadata { //Returns the name of the provider that will be shown in the AD FS management UI (not visible to end users) public string AdminName { get { return "My Example MFA Adapter"; } } //Returns an array of strings containing URIs indicating the set of authentication methods implemented by the adapter /// AD FS requires that, if authentication is successful, the method actually employed will be returned by the /// final call to TryEndAuthentication(). If no authentication method is returned, or the method returned is not /// one of the methods listed in this property, the authentication attempt will fail. public virtual string[] AuthenticationMethods { get { return new[] { "http://example.com/myauthenticationmethod1", "http://example.com/myauthenticationmethod2" }; } } /// Returns an array indicating which languages are supported by the provider. AD FS uses this information /// to determine the best language\locale to display to the user. public int[] AvailableLcids { get { return new[] { new CultureInfo("en-us").LCID, new CultureInfo("fr").LCID}; } } /// Returns a Dictionary containing the set of localized friendly names of the provider, indexed by lcid. /// These Friendly Names are displayed in the "choice page" offered to the user when there is more than /// one secondary authentication provider available. public Dictionary<int, string> FriendlyNames { get { Dictionary<int, string> _friendlyNames = new Dictionary<int, string>(); _friendlyNames.Add(new CultureInfo("en-us").LCID, "Friendly name of My Example MFA Adapter for end users (en)"); _friendlyNames.Add(new CultureInfo("fr").LCID, "Friendly name translated to fr locale"); return _friendlyNames; } } /// Returns a Dictionary containing the set of localized descriptions (hover over help) of the provider, indexed by lcid. /// These descriptions are displayed in the "choice page" offered to the user when there is more than one /// secondary authentication provider available. public Dictionary<int, string> Descriptions { get { Dictionary<int, string> _descriptions = new Dictionary<int, string>(); _descriptions.Add(new CultureInfo("en-us").LCID, "Description of My Example MFA Adapter for end users (en)"); _descriptions.Add(new CultureInfo("fr").LCID, "Description translated to fr locale"); return _descriptions; } } /// Returns an array indicating the type of claim that the adapter uses to identify the user being authenticated. /// Note that although the property is an array, only the first element is currently used. /// MUST BE ONE OF THE FOLLOWING /// "http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname" /// "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn" /// "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress" /// "http://schemas.microsoft.com/ws/2008/06/identity/claims/primarysid" public string[] IdentityClaims { get { return new[] { "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn" }; } } //All external providers must return a value of "true" for this property. public bool RequiresIdentity { get { return true; } } }
现在,你应该能够对 IAuthenticationAdapter 按 F12(右键单击,然后选择“转到定义”),查看所需接口成员集。
接下来,可执行这些项的实现。
将类的全部内容替换为以下信息:
namespace MFAadapter { class MyAdapter : IAuthenticationAdapter { public IAuthenticationAdapterMetadata Metadata { //get { return new <instance of IAuthenticationAdapterMetadata derived class>; } } public IAdapterPresentation BeginAuthentication(Claim identityClaim, HttpListenerRequest request, IAuthenticationContext authContext) { //return new instance of IAdapterPresentationForm derived class } public bool IsAvailableForUser(Claim identityClaim, IAuthenticationContext authContext) { return true; //its all available for now } public void OnAuthenticationPipelineLoad(IAuthenticationMethodConfigData configData) { //this is where AD FS passes us the config data, if such data was supplied at registration of the adapter } public void OnAuthenticationPipelineUnload() { } public IAdapterPresentation OnError(HttpListenerRequest request, ExternalAuthenticationException ex) { //return new instance of IAdapterPresentationForm derived class } public IAdapterPresentation TryEndAuthentication(IAuthenticationContext authContext, IProofData proofData, HttpListenerRequest request, out Claim[] outgoingClaims) { //return new instance of IAdapterPresentationForm derived class } } }
接着,添加表示形式:
class MyPresentationForm : IAdapterPresentationForm { /// Returns the HTML Form fragment that contains the adapter user interface. This data will be included in the web page that is presented /// to the cient. public string GetFormHtml(int lcid) { string htmlTemplate = Resources.FormPageHtml; //todo we will implement this return htmlTemplate; } /// Return any external resources, ie references to libraries etc., that should be included in /// the HEAD section of the presentation form html. public string GetFormPreRenderHtml(int lcid) { return null; } //returns the title string for the web page which presents the HTML form content to the end user public string GetPageTitle(int lcid) { return "MFA Adapter"; } }
请注意上述 Resources.FormPageHtml 元素的“待办事项”。 一分钟内即可修复它,但首先,让我们根据新实现的类型将最终所需的返回语句添加到初始 MyAdapter 类。 为此,请将以下内容添加到现有 IAuthenticationAdapter 实现:
class MyAdapter : IAuthenticationAdapter { public IAuthenticationAdapterMetadata Metadata { //get { return new <instance of IAuthenticationAdapterMetadata derived class>; } get { return new MyMetadata(); } } public IAdapterPresentation BeginAuthentication(Claim identityClaim, HttpListenerRequest request, IAuthenticationContext authContext) { //return new instance of IAdapterPresentationForm derived class return new MyPresentationForm(); } public bool IsAvailableForUser(Claim identityClaim, IAuthenticationContext authContext) { return true; //its all available for now } public void OnAuthenticationPipelineLoad(IAuthenticationMethodConfigData configData) { //this is where AD FS passes us the config data, if such data was supplied at registration of the adapter } public void OnAuthenticationPipelineUnload() { } public IAdapterPresentation OnError(HttpListenerRequest request, ExternalAuthenticationException ex) { //return new instance of IAdapterPresentationForm derived class return new MyPresentationForm(); } public IAdapterPresentation TryEndAuthentication(IAuthenticationContext authContext, IProofData proofData, HttpListenerRequest request, out Claim[] outgoingClaims) { //return new instance of IAdapterPresentationForm derived class outgoingClaims = new Claim[0]; return new MyPresentationForm(); } }
现在,对于包含 html 片段的资源文件, 在项目文件夹中新建一个包含以下内容的文本文件:
<div id="loginArea"> <form method="post" id="loginForm" > <!-- These inputs are required by the presentation framework. Do not modify or remove --> <input id="authMethod" type="hidden" name="AuthMethod" value="%AuthMethod%" /> <input id="context" type="hidden" name="Context" value="%Context%" /> <!-- End inputs are required by the presentation framework. --> <p id="pageIntroductionText">This content is provided by the MFA sample adapter. Challenge inputs should be presented below.</p> <label for="challengeQuestionInput" class="block">Question text</label> <input id="challengeQuestionInput" name="ChallengeQuestionAnswer" type="text" value="" class="text" placeholder="Answer placeholder" /> <div id="submissionArea" class="submitMargin"> <input id="submitButton" type="submit" name="Submit" value="Submit" onclick="return AuthPage.submitAnswer()"/> </div> </form> <div id="intro" class="groupMargin"> <p id="supportEmail">Support information</p> </div> <script type="text/javascript" language="JavaScript"> //<![CDATA[ function AuthPage() { } AuthPage.submitAnswer = function () { return true; }; //]]> </script> </div>
然后,选择“项目”->“添加组件...”->“资源文件”,将文件命名为 Resources,然后单击“添加”:
然后,在 Resources.resx 文件中,选择“添加资源...”和“添加现有文件”。 导航到上面保存的文本文件(包含 html 片段)。
确保 GetFormHtml 代码按资源文件(.resx 文件)名称前缀后跟资源本身的名称来正确解析新资源的名称:
public string GetFormHtml(int lcid) { string htmlTemplate = Resources.MfaFormHtml; //Resxfilename.resourcename return htmlTemplate; }
现在,应该能够进行生成了。
生成适配器
适配器应内置在可安装到 Windows GAC 中的强名称 .NET 程序集中。 要在 Visual Studio 项目中实现此目的,请完成以下步骤:
在解决方案资源管理器中右键单击项目名称,然后单击“属性”。
在“签名”选项卡上,检查“对程序集签名”,然后在“选择强名称密钥文件”下选择“新建...”:输入密钥文件名和密码,然后单击“确定”。<> 然后,确保选中“对程序集签名”,并且未勾选“仅延迟签名”。 属性签名页应如下所示:
然后,生成解决方案。
将适配器部署到 AD FS 测试计算机
必须先在系统中注册外部提供程序,然后 AD FS 才能调用该提供程序。 适配器提供程序必须提供执行必要安装操作(包括在 GAC 中安装)的安装程序,而且安装程序必须支持在 AD FS 中注册。 如果未执行此操作,管理员需要执行下面的 Windows PowerShell 步骤。 可在实验室中使用这些步骤来启用测试和调试。
准备 AD FS 测试计算机
复制文件并将其添加到 GAC。
确保具有 Windows Server 2012 R2 计算机或虚拟机。
安装 AD FS 角色服务并配置包含至少一个节点的场。
有关在实验室环境中设置联合服务器的详细步骤,请参阅 Windows Server 2012 R2 AD FS 部署指南。
将 Gacutil.exe 工具复制到服务器。
可在 Windows 8 计算机上的“%homedrive%Program Files (x86)Microsoft SDKsWindowsv8.0AbinNETFX 4.0 Tools”中找到 Gacutil.exe。 需要 gacutil.exe 文件本身,还需要 NETFX 4.0 Tools 位置下的 1033、en-US 和其他本地化资源文件夹。
将提供程序文件(一个或多个强名称签名 .dll 文件)复制到 gacutil.exe 所在的文件夹位置(提供此位置仅为方便查看)
将 .dll 文件添加到场中每个 AD FS 联合服务器上的 GAC:
示例:使用命令行工具 GACutil.exe 将 dll 添加到 GAC:
C:>.gacutil.exe /if .<yourdllname>.dll
若要在 GAC 中查看生成的条目,请使用
C:>.gacutil.exe /l <yourassemblyname>
在 AD FS 中注册提供程序
满足上述先决条件后,在联合服务器上打开 Windows PowerShell 命令窗口,并输入以下命令(请注意,如果使用的联合服务器场在使用Windows 内部数据库,则必须在场的主联合服务器上执行这些命令):
Register-AdfsAuthenticationProvider –TypeName YourTypeName –Name “AnyNameYouWish” [–ConfigurationFilePath (optional)]
其中,YourTypeName 是 .NET 强类型名称:“YourDefaultNamespace.YourIAuthenticationAdapterImplementationClassName, YourAssemblyName, Version=YourAssemblyVersion, Culture=neutral, PublicKeyToken=YourPublicKeyTokenValue, processorArchitecture=MSIL”
这将在 AD FS 中注册外部提供程序,并使用上面提供的名称 AnyNameYouWish。
重启 AD FS 服务(例如,通过使用 Windows 服务管理单元)。
运行以下命令:
Get-AdfsAuthenticationProvider
。这会将你的提供程序显示为系统中的提供程序之一。
例如:
$typeName = "MFAadapter.MyAdapter, MFAadapter, Version=1.0.0.0, Culture=neutral, PublicKeyToken=e675eb33c62805a0, processorArchitecture=MSIL” Register-AdfsAuthenticationProvider -TypeName $typeName -Name “MyMFAAdapter” net stop adfssrv net start adfssrv
如果在 AD FS 环境中启用了设备注册服务,则还要执行 PowerShell 命令
net start drs
若要验证已注册的提供程序,请使用 PowerShell 命令
Get-AdfsAuthenticationProvider
。这会将你的提供程序显示为系统中的提供程序之一。
创建调用适配器的 AD FS 身份验证策略
使用 AD FS 管理单元创建身份验证策略
从服务器管理器的“工具”菜单打开 AD FS 管理单元。
单击“身份验证策略”。
在中间窗格的“多重身份验证”下,单击“全局设置”右侧的“编辑”链接。
在页面底部的“选择其他身份验证方法”下,检查提供程序的 AdminName 框。 单击 “应用”。
若要提供使用适配器调用 MFA 的“触发器”,请在“位置”下检查 Extranet 和 Intranet 等等。 单击“确定” 。 (若要配置每个信赖方的触发器,请参阅下面的“使用 Windows PowerShell 创建身份验证策略”。)
使用以下命令检查结果:
首先使用
Get-AdfsGlobalAuthenticationPolicy
。 你应该会看到提供程序名称为 AdditionalAuthenticationProvider 值之一。然后使用
Get-AdfsAdditionalAuthenticationRule
。 应该会看到在管理员 UI 中选择策略后配置的 Extranet 和 Intranet 规则。
使用 Windows PowerShell 创建身份验证策略
首先,在全局策略中启用提供程序:
Set-AdfsGlobalAuthenticationPolicy -AdditionalAuthenticationProvider “YourAuthProviderName”`
注意
请注意,为 AdditionalAuthenticationProvider 参数提供的值对应于在上述 Register-AdfsAuthenticationProvider cmdlet 中为“Name”参数提供的值,并且对应于 Get-AdfsAuthenticationProvider cmdlet 输出中的“Name”属性。
Set-AdfsGlobalAuthenticationPolicy –AdditionalAuthenticationProvider “MyMFAAdapter”`
接下来,配置全局或特定于信赖方的规则来触发 MFA:
示例 1:创建全局规则以要求对外部请求执行 MFA:
Set-AdfsAdditionalAuthenticationRule –AdditionalAuthenticationRules 'c:[type == "http://schemas.microsoft.com/ws/2012/01/insidecorporatenetwork", value == "false"] => issue(type = "http://schemas.microsoft.com/ws/2008/06/identity/claims/authenticationmethod", value = "http://schemas.microsoft.com/claims/multipleauthn" );'
示例 2:创建 MFA 规则以要求对特定信赖方的外部请求执行 MFA。 (注意:在 Windows Server 2012 R2 中,单个提供程序不能连接到 AD FS 中的单个信赖方。)
$rp = Get-AdfsRelyingPartyTrust –Name <Relying Party Name> Set-AdfsRelyingPartyTrust –TargetRelyingParty $rp –AdditionalAuthenticationRules 'c:[type == "http://schemas.microsoft.com/ws/2012/01/insidecorporatenetwork", value == "false"] => issue(type = "http://schemas.microsoft.com/ws/2008/06/identity/claims/authenticationmethod", value = "http://schemas.microsoft.com/claims/multipleauthn" );'
使用适配器通过 MFA 进行身份验证
最后,执行以下步骤来测试适配器:
对于 Extranet 和 Intranet,都请确保 AD FS 全局主要身份验证类型配置为表单身份验证(这样一来,演示可更轻松地以特定用户的身份进行身份验证)
在 AD FS 管理单元的“身份验证策略”下的“主要身份验证”区域中,单击“全局设置”旁边的“编辑”。
- 或者,只需单击“多重策略”UI 中的“主要”选项卡。
确保表单身份验证是针对 Extranet 和 Intranet 身份验证方法选中的唯一选项。 单击“确定” 。
打开 IDP 发起的登录 html 页 (https://<fsname>/adfs/ls/idpinitiatedsignon.htm),并在测试环境中以有效 AD 用户的身份登录。
输入用于主要身份验证的凭据。
应该会看到 MFA 表单页面,其中显示了示例质询问题。
如果配置了多个适配器,则会看到上面带有易记名称的 MFA 选择页。
现在,你拥有了正常运行的的接口实现,还了解了模型的工作原理。 可在 BeginAuthentication 和 TryEndAuthentication 中尝试设置断点,作为额外的示例。 请注意在用户首次进入 MFA 表单时执行 BeginAuthentication 的方式,而 TryEndAuthentication 是在每次提交表单时触发的。
更新适配器以成功进行身份验证
但请稍等 - 示例适配器的身份验证永远不会成功! 这是因为代码中的内容均不对 TryEndAuthentication 返回 Null。
完成上述过程后,你创建了一个基本的适配器实现,并将其添加到了 AD FS 服务器。 可获取 MFA 表单页,但你尚未进行身份验证,因为你尚未在 TryEndAuthentication 实现中放入正确的逻辑。 所以,让我们来添加它。
回顾一下 TryEndAuthentication 实现:
public IAdapterPresentation TryEndAuthentication(IAuthenticationContext authContext, IProofData proofData, HttpListenerRequest request, out Claim[] outgoingClaims)
{
//return new instance of IAdapterPresentationForm derived class
outgoingClaims = new Claim[0];
return new MyPresentationForm();
}
让我们更新它,使其不总是返回 always return MyPresentationForm()。 为此,可在类中创建一个简单的实用工具方法:
static bool ValidateProofData(IProofData proofData, IAuthenticationContext authContext)
{
if (proofData == null || proofData.Properties == null || !proofData.Properties.ContainsKey("ChallengeQuestionAnswer"))
{
throw new ExternalAuthenticationException("Error - no answer found", authContext);
}
if ((string)proofData.Properties["ChallengeQuestionAnswer"] == "adfabric")
{
return true;
}
else
{
return false;
}
}
然后,按如下所示更新 TryEndAuthentication:
public IAdapterPresentation TryEndAuthentication(IAuthenticationContext authContext, IProofData proofData, HttpListenerRequest request, out Claim[] outgoingClaims)
{
outgoingClaims = new Claim[0];
if (ValidateProofData(proofData, authContext))
{
//authn complete - return authn method
outgoingClaims = new[]
{
// Return the required authentication method claim, indicating the particulate authentication method used.
new Claim( "http://schemas.microsoft.com/ws/2008/06/identity/claims/authenticationmethod", "http://example.com/myauthenticationmethod1" )
};
return null;
}
else
{
//authentication not complete - return new instance of IAdapterPresentationForm derived class
return new MyPresentationForm();
}
}
现在,必须更新测试框上的适配器。 必须先撤消 AD FS 策略,从 AD FS 注销再重启 AD FS,从 GAC 中移除 .dll,将新的 .dll 添加到 GAC,然后在 AD FS 中注册它,重启 AD FS,接下来重新配置 AD FS 策略。
在 AD FS 测试计算机上部署和配置更新后的适配器
清除 AD FS 策略
清除 MFA UI 中与 MFA 相关的所有复选框(如下所示),然后单击“确定”。
注销提供程序 (Windows PowerShell)
PS C:> Unregister-AdfsAuthenticationProvider –Name “YourAuthProviderName”
示例:PS C:> Unregister-AdfsAuthenticationProvider –Name “MyMFAAdapter”
传递给“名称”的值与为 Register-AdfsAuthenticationProvider cmdlet 提供的“名称”的值相同。 它也是 Get-AdfsAuthenticationProvider 输出的“Name”属性。
在注销提供程序之前,必须清除 AD FS 管理单元中已勾选的复选框或使用 Windows PowerShell 从 AdfsGlobalAuthenticationPolicy 中移除提供程序。
执行此操作后,必须重启 AD FS 服务。
从 GAC 中移除程序集
首先,使用以下命令查找条目的完全限定强名称:
C:>.gacutil.exe /l <yourAdapterAssemblyName>
示例:
C:>.gacutil.exe /l mfaadapter
然后,使用以下命令将其从 GAC 中移除:
.gacutil /u “<output from the above command>”
示例:
C:>.gacutil /u “mfaadapter, Version=1.0.0.0, Culture=neutral, PublicKeyToken=e675eb33c62805a0, processorArchitecture=MSIL”
将更新后的程序集添加到 GAC
请确保先在本地粘贴已更新的 .dll。 C:>.gacutil.exe /if .MFAAdapter.dll
在 GAC (cmd line) 中查看程序集
C:> .gacutil.exe /l mfaadapter
在 AD FS 中注册提供程序
PS C:>$typeName = "MFAadapter.MyAdapter, MFAadapter, Version=1.0.0.1, Culture=neutral, PublicKeyToken=e675eb33c62805a0, processorArchitecture=MSIL”
PS C:>Register-AdfsAuthenticationProvider -TypeName $typeName -Name “MyMFAAdapter1”
重启 AD FS 服务。
使用 AD FS 管理单元创建身份验证策略
从服务器管理器的“工具”菜单打开 AD FS 管理单元。
单击“身份验证策略”。
在“多重身份验证”下,单击“全局设置”右侧的“编辑”链接。
在“选择其他身份验证方法”下,检查提供程序的 AdminName 框。 单击 “应用”。
若要提供使用适配器调用 MFA 的“触发器”,请在“位置”下检查 Extranet 和 Intranet 等等。 单击“确定” 。
使用适配器通过 MFA 进行身份验证
最后,执行以下步骤来测试适配器:
对于 Extranet 和 Intranet,都请确保 AD FS 全局主要身份验证类型配置为表单身份验证(这样一来,可更轻松地以特定用户的身份进行身份验证)。
在 AD FS 管理单元的“身份验证策略”下的“主要身份验证”区域中,单击“全局设置”旁边的“编辑”。
- 或者,只需单击“多重策略”UI 中的“主要”选项卡。
确保表单身份验证是针对 Extranet 和 Intranet 身份验证方法选中的唯一选项。 单击“确定” 。
打开 IDP 发起的登录 html 页 (https://<fsname>/adfs/ls/idpinitiatedsignon.htm),并在测试环境中以有效 AD 用户的身份登录。
输入用于主要身份验证的凭据。
应该会看到 MFA 表单页面,其中显示了示例质询文本。
- 如果配置了多个适配器,则会看到带有易记名称的 MFA 选择页。
在 MFA 身份验证页中输入 adfabric 时,应该会看到成功登录。