在 Windows Server 中为 AD FS 生成自定义身份验证方法

本演练提供有关在 Windows Server 2012 R2 中为 AD FS 实现自定义身份验证方法的说明。 有关详细信息,请参阅 其他身份验证方法

警告

可以在此处构建的示例仅用于教育目的。  这些说明适用于最简单、最简的实现,以显示模型所需的元素。  没有身份验证后端、错误处理或配置数据。

设置开发工具箱

本演练使用 Visual Studio 2012。 可以使用可为 Windows 创建 .NET 类的任何开发环境生成项目。 项目必须面向 .NET 4.5,因为 BeginAuthenticationTryEndAuthentication 方法使用 .NET Framework 版本 4.5 的 System.Security.Claims.Claim 类型。 项目需要一个引用:

引用 dll 在哪里找到 要求
Microsoft.IdentityServer.Web.dll 该 dll 位于已安装 AD FS 的 Windows Server 2012 R2 服务器上的 %windir%\ADFS 中。

此 dll 必须复制到开发计算机上,并在项目中创建显式引用。

接口类型,包括 IAuthenticationContext、IProofData

创建提供程序

  1. 在 Visual Studio 2012 中,选择“文件”->“新建”->“项目...”

  2. 选择类库并确保以 .NET 4.5 为目标。

    “新建项目”对话框的屏幕截图,其中选择了“类库”选项。

  3. 在已安装 AD FS 的 Windows Server 2012 R2 服务器上从 %windir%\ADFS 复制 Microsoft.IdentityServer.Web.dll ,并将其粘贴到开发计算机上的 Project 文件夹中。

  4. 解决方案资源管理器中,右键单击 “引用 ”并 添加引用...

  5. 浏览到 Microsoft.IdentityServer.Web.dll 的本地副本,然后选择“添加...”

  6. 单击“ 确定” 以确认新引用:

    “引用管理器”对话框的屏幕截图,其中显示了所选 Microsoft.IdentityServer.Web.dll。

    现在应设置为解析提供程序需要的所有类型。

  7. 向项目添加新类(右键单击项目, 添加...类...)并为其命名,如 MyAdapter,如下所示:

    “添加新项”对话框的屏幕截图,其中选择了“类”选项。

  8. 在新文件中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
            }
    
        }
    }
    
  9. 我们尚未准备好进行生成...还有两个接口要处理。

    将另外两个类添加到项目:一个是用于元数据,另一个用于演示文稿窗体。 可以在与上述类相同的文件中添加这些内容。

    class MyMetadata : IAuthenticationAdapterMetadata
    {
    
    }
    
    class MyPresentationForm : IAdapterPresentationForm
    {
    
    }
    
  10. 接下来,可以为每个项添加所需的成员。首先,添加元数据(附上有用的内联注释)

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

    现在,你应该能够 F12(右键单击 – 转到定义)在 IAuthenticationAdapter 上查看所需的接口成员集。

    接下来,可执行这些项的实现。

  11. 将类的全部内容替换为以下信息:

    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";
        }
    }
    
  12. 请注意上述 Resources.FormPageHtml 元素的“待办事项”。 可以在一分钟内修复它,但首先,让我们根据新实现的类型将最终所需的 return 语句添加到初始 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();
        }
    
    }
    
  13. 现在,对于包含 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>
    
  14. 然后选择Project-Add Component... Resources 文件,将文件命名为 Resources,然后单击添加:

    “添加新项”对话框的屏幕截图,显示已选择“资源文件”。

  15. 然后,在 Resources.resx 文件中,选择 “添加资源...”添加现有文件。 导航到上面保存的文本文件(包含 html 片段)。

    确保 GetFormHtml 代码按资源文件(.resx 文件)名称前缀后跟资源本身的名称来正确解析新资源的名称:

    public string GetFormHtml(int lcid)
    {
        string htmlTemplate = Resources.MfaFormHtml; //Resxfilename.resourcename
        return htmlTemplate;
    }
    

现在,应该能够进行生成了。

生成适配器

适配器应内置在可安装到 Windows GAC 中的强名称 .NET 程序集中。 若要在 Visual Studio 项目中实现此目的,请完成以下步骤:

  1. 在解决方案资源管理器中右键单击项目名称,然后单击“ 属性”。

  2. 在“签名”选项卡上,选中“对程序集进行签名”,然后在“选择强名称密钥文件”下选择<“新建>...”:输入密钥文件名和密码,然后单击“确定”。 然后,确保选中“对程序集签名”,并且未勾选“仅延迟签名”。属性签名 ”页应如下所示:

    生成提供程序

  3. 然后生成解决方案。

将适配器部署到 AD FS 测试计算机

必须先在系统中注册外部提供程序,然后 AD FS 才能调用外部提供程序。 适配器提供程序必须提供一个安装程序,该安装程序必须执行必要的安装作,包括 GAC 中的安装,并且安装程序必须支持在 AD FS 中注册。 如果未执行此作,管理员需要执行下面的 Windows PowerShell 步骤。 可以在实验室中使用这些步骤以便进行测试和调试。

准备测试 AD FS 计算机

复制文件并添加到 GAC。

  1. 确保拥有 Windows Server 2012 R2 计算机或虚拟机。

  2. 安装 AD FS 角色服务并配置一个至少包含一个节点的服务器场。

    有关在实验室环境中设置联合服务器的详细步骤,请参阅 Windows Server 2012 R2 AD FS 部署指南

  3. 将 Gacutil.exe 工具复制到服务器。

    Gacutil.exe 可在 Windows 8 计算机上的%homedrive%Program 文件 (x86)Microsoft SDKsWindowsv8.0AbinNETFX 4.0 Tools 中找到。 需要 gacutil.exe 文件本身和 1033en-US,以及 NETFX 4.0 工具 位置下的其他本地化资源文件夹。

  4. 将提供程序文件(一个或多个强名称签名 .dll 文件)复制到 gacutil.exe 所在的文件夹位置(提供此位置仅为方便查看)

  5. 将 .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 内部数据库的联合服务器场,则必须在场的主联合服务器上执行这些命令):

  1. Register-AdfsAuthenticationProvider –TypeName YourTypeName –Name “AnyNameYouWish” [–ConfigurationFilePath (optional)]

    其中,YourTypeName 是 .NET 强类型名称:“YourDefaultNamespace.YourIAuthenticationAdapterImplementationClassName, YourAssemblyName, Version=YourAssemblyVersion, Culture=neutral, PublicKeyToken=YourPublicKeyTokenValue, processorArchitecture=MSIL”

    这将在 AD FS 中注册外部提供程序,并使用上面提供的名称 AnyNameYouWish。

  2. 重启 AD FS 服务(例如,通过使用 Windows 服务管理单元)。

  3. 运行以下命令: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 管理单元创建身份验证策略

  1. 从服务器管理器的“工具”菜单打开 AD FS 管理单元。

  2. 单击 “身份验证策略”。

  3. 在中心窗格中的“多重身份验证”下,单击“全局设置”右侧的“编辑”链接。

  4. 在页面底部的“选择其他身份验证方法”下,检查提供程序的 AdminName 框。 单击“应用”

  5. 若要提供使用适配器调用 MFA 的“触发器”,请在 “位置 ”下检查 ExtranetIntranet,例如。 单击“ 确定”。 (若要为每个信赖方配置触发器,请参阅下面的“使用 Windows PowerShell 创建身份验证策略”。

  6. 使用以下命令检查结果:

    第一次使用 Get-AdfsGlobalAuthenticationPolicy。 你应该会看到提供程序名称为 AdditionalAuthenticationProvider 值之一。

    然后使用Get-AdfsAdditionalAuthenticationRule。 在管理员 UI 中选择策略后,应会看到 Extranet 和 Intranet 的规则。

使用 Windows PowerShell 创建身份验证策略

  1. 首先,在全局策略中启用提供程序:

    Set-AdfsGlobalAuthenticationPolicy -AdditionalAuthenticationProvider “YourAuthProviderName”`
    

    注释

    请注意,为 AdditionalAuthenticationProvider 参数提供的值对应于为上述 Register-AdfsAuthenticationProvider cmdlet 中提供的“Name”参数的值,以及来自 Get-AdfsAuthenticationProvider cmdlet 输出的“Name”属性。

    Set-AdfsGlobalAuthenticationPolicy –AdditionalAuthenticationProvider “MyMFAAdapter”`
    
  2. 接下来,配置全局规则或信赖方特定的规则以触发 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 进行身份验证

最后,执行以下步骤来测试适配器:

  1. 对于 Extranet 和 Intranet,都请确保 AD FS 全局主要身份验证类型配置为表单身份验证(这样一来,演示可更轻松地以特定用户的身份进行身份验证)

    1. 在 AD FS 管理单元的“身份验证策略”下,在“主要身份验证”区域中,单击“全局设置”旁边的“编辑”。

      1. 或者,只需单击多重策略 UI 中的“主要”选项卡即可。
  2. 确保 窗体身份验证 是 Extranet 和 Intranet 身份验证方法中唯一选中的选项。 单击“ 确定”。

  3. 打开 IDP 发起的登录 html 页(https://< fsname>/adfs/ls/idpinitiatedsignon.htm),并在测试环境中以有效的 AD 用户身份登录。

  4. 输入主要身份验证的凭据。

  5. 您应该会看到“MFA 表单”页面,上面显示了示例质询问题。

    如果配置了多个适配器,则会看到上面带有易记名称的 MFA 选择页。

    M F A 窗体页的屏幕截图,其中包含示例质询问题。

    M F A 选项页的屏幕截图。

现在,你已拥有接口的工作实现,并且你已了解模型的工作原理。 可以尝试作为额外的示例在 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();
}

让我们对其进行更新,这样它并不总是返回 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 中移除程序集

  1. 首先,使用以下命令查找条目的完全限定强名称:C:>.gacutil.exe /l <yourAdapterAssemblyName>

    示例:C:>.gacutil.exe /l mfaadapter

  2. 然后,使用以下命令将其从 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 中的程序集(命令行)

C:> .gacutil.exe /l mfaadapter

在 AD FS 中注册提供程序

  1. PS C:>$typeName = "MFAadapter.MyAdapter, MFAadapter, Version=1.0.0.1, Culture=neutral, PublicKeyToken=e675eb33c62805a0, processorArchitecture=MSIL”

  2. PS C:>Register-AdfsAuthenticationProvider -TypeName $typeName -Name “MyMFAAdapter1”

  3. 重启 AD FS 服务。

使用 AD FS 管理单元创建身份验证策略

  1. 从服务器管理器的“工具”菜单打开 AD FS 管理单元。

  2. 单击 “身份验证策略”。

  3. “多重身份验证”下,单击“全局设置”右侧的“编辑”链接。

  4. 在“选择其他身份验证方法”下,检查提供程序的 AdminName 框。 单击“应用”

  5. 若要提供使用适配器调用 MFA 的“触发器”,请在“位置”下检查 ExtranetIntranet,例如。 单击“ 确定”。

使用适配器通过 MFA 进行身份验证

最后,执行以下步骤来测试适配器:

  1. 确保将 AD FS 全局主身份验证类型配置为 窗体身份验证,适用于 Extranet 和 Intranet,这样可以更容易地作为特定用户进行身份验证。

    1. 在 AD FS 管理管理单元的“身份验证策略”下,在“主要身份验证”区域中,单击“全局设置”旁边的“编辑”。

      1. 或者,只需单击多重策略 UI 中的 “主要 ”选项卡即可。
  2. 确保表单身份验证是针对 Extranet 和 Intranet 身份验证方法选中的唯一选项。 单击“ 确定”。

  3. 打开 IDP 发起的登录 html 页(https://< fsname>/adfs/ls/idpinitiatedsignon.htm),并在测试环境中以有效的 AD 用户身份登录。

  4. 输入主要身份验证的凭据。

  5. 您应该看到“MFA 表单”页面,其中会显示示例验证文本。

    1. 如果配置了多个适配器,则会看到带有易记名称的 MFA 选择页。

在 MFA 身份验证页中输入 adfabric 时,应会看到一个成功的登录。

M F A 表单页面的屏幕截图,其中包含示例验证文本。

M F A 成功登录页的屏幕截图。

另请参阅

其他资源

其他身份验证方法

使用敏感应用程序的其他多重身份验证管理风险