增量式ASP.NET迁移工具预览版2安装教程及使用演示

207 阅读10分钟

上个月,我们推出了预览工具,以逐步将ASP.NET应用程序迁移到ASP.NET Core。该工具由两个部分组成:一个是Visual Studio扩展,在现有的ASP.NET应用旁边创建一个新的ASP.NET Core应用,这样端点就可以逐渐从一个应用转移到另一个应用;另一个是System.Web适配器API库,允许代码引用常见的System.Web API,同时以.NET标准2.0为目标,可以在ASP.NET和ASP.NET Core环境下使用。

我们最近发布了这个ASP.NET迁移工具的预览版2。更新后的工具包括对Visual Studio扩展生成的代码的改进,适配器库中额外的System.Web表面区域,以及在ASP.NET和ASP.NET Core应用程序之间共享认证的能力,这样,即使用户的浏览体验涉及新旧应用程序提供的端点,也只需登录一次。

作为提醒,System.Web适配器的开发正在GitHub上进行。在该资源库中,你可以找到文档,浏览最新的源代码,或者通过创建问题或拉动请求来贡献。

开始使用

如果这是你第一次测试增量ASP.NET迁移工具,你需要安装Microsoft Project MigrationsVisual Studio扩展。

当你使用该扩展来迁移ASP.NET项目时,它会自动添加对System.Web适配器预览2版本的引用。但如果你需要直接引用System.Web适配器(例如在类库中使用它们),可以从NuGet安装:<PackageReference Include="Microsoft.AspNetCore.SystemWebAdapters" Version="1.0.0-preview.2.22316.1" />

升级迁移工具

如果你以前测试过增量ASP.NET迁移工具的预览版1,你可以直接从Visual Studio中更新Microsoft Project Migrations Visual Studio扩展。只要点击扩展菜单中的 "管理扩展 "命令。在那里,进入更新标签,寻找 "Microsoft Project Migrations "并点击更新按钮。

Updating the migration VS extension

要更新对System.Web适配器的现有引用,只需更新到NuGet包的预览2版本:1.0.0-preview.2.22316.1

共享认证

上一篇博文解释了增量迁移和System.Web适配器的总体工作原理。在预览版2中,我们为正在迁移到ASP.NET Core的应用程序增加了在新旧项目之间共享认证的功能。这是通过将认证决定推迟到原始的ASP.NET应用程序来实现的。当应用程序选择共享认证时,一个认证处理程序被注册到ASP.NET Core应用程序中,该程序通过向ASP.NET应用程序发出HTTP请求来认证用户,其中包括与认证相关的头信息(默认为AuthorizationCookie 头信息,但这是可以配置的)。ASP.NET应用程序中的一个自定义HTTP处理程序将为该请求提供服务,并根据请求中的头信息为被认证的用户返回一个序列化的索赔委托。

如果ASP.NET应用程序无法验证一个用户(也许还没有人登录),就不会返回任何索赔委托书。相反,ASP.NET应用程序将返回HTTP状态代码和与认证相关的响应头(默认为LocationSet-CookieWWW-Authenticate ),如果用户直接试图访问ASP.NET应用程序中需要授权的端点,它就会返回这些响应头。这些值存储在ASP.NET Core应用程序中,如果认证受到挑战(例如,因为用户正在访问受保护的端点),它们将被用来向用户返回HTTP响应,该响应与直接从ASP.NET应用程序收到的挑战响应类似。

因为在挑战的情况下,来自ASP.NET应用程序的响应可能与来自ASP.NET核心应用程序的响应不完全一致(例如,重定向位置需要固定,以引用正确的主机和原始路径),在将ASP.NET应用程序的响应传递给终端用户之前,会对其进行一些处理。System.Web适配器已经修复了与主机和重定向路径有关的已知问题,但如果你的特定认证方案需要对来自ASP.NET应用程序的响应进行额外的修改,你可以实现Microsoft.AspNetCore.SystemWebAdapters.Authentication.IRemoteAppAuthenticationResultProcessor 接口,并在ASP.NET Core应用程序的依赖注入容器中注册该实现。

Diagram of remote authentication workflow

已知的限制

远程应用程序认证适用于不记名令牌和基于cookie的认证方案。它目前不能与Windows认证一起使用,已知WS-Federation认证存在一些问题,正在调查中。

还需要注意的是,在ASP.NET身份认证方案中从ASP.NET核心应用中注销是不可行的,因为在这些方案中注销是通过向ASP.NET应用发出POST请求来完成的,由于防伪令牌验证在两个应用之间不工作,所以目前是不允许的。作为一个临时的解决方法,应用程序可以让注销操作将用户重定向到ASP.NET应用程序托管的页面,并让用户从那里注销。

演练

让我们通过一个例子来了解如何在增量的ASP.NET迁移方案中开始使用共享认证。

创建初始应用程序

首先,创建一个新的ASP.NET MVC应用程序,并选择 "个人账户 "进行认证。这将为我们提供一个包括ASP.NET身份认证的迁移起点。

Creating a new sample MVC project

启动该应用程序以确保其工作,并注册一个用户。

创建迁移项目

现在,在Visual Studio的解决方案资源管理器中右击该项目,选择 "迁移项目",使用项目迁移扩展来设置一个新的ASP.NET Core应用程序,它将与这个应用程序一起运行和部署,并允许我们逐步将端点迁移过来。请确保选择一个MVC模板,因为最初的应用程序是MVC。

Using the Project Migrations extension to create a migration project

新项目已经有了对Microsoft.AspNetCore.SystemWebAdapters 的引用,但我们需要在原来的ASP.NET应用程序中添加对该包的引用,以便它能在ASP.NET端配置远程应用程序端点。右键单击原始应用程序的引用文件夹,选择 "管理NuGet包 "并添加对Microsoft.AspNetCore.SystemWebAdapters 包的引用。

配置远程应用程序的认证

在这一点上,我们已经创建了新的ASP.NET Core应用程序,并将它不能提供的请求代理给原ASP.NET应用程序。我们现在需要配置远程应用程序认证,以便在两个应用程序之间共享用户身份。

在ASP.NET Core应用程序的Program.cs文件中,在现有的AddSystemWebAdapters 调用之后添加一个对AddRemoteAppAuthentication 的调用,如这里所示:

builder.Services.AddSystemWebAdapters()
    .AddRemoteAppAuthentication(true, options =>
     {
         options.RemoteServiceOptions.RemoteAppUrl = 
            new(builder.Configuration["ReverseProxy:Clusters:fallbackCluster:Destinations:fallbackApp:Address"]);
         options.RemoteServiceOptions.ApiKey = "test-key";
     });

这将注册远程应用程序的认证处理程序。

传递给AddRemoteAppAuthentication 的第一个参数是一个布尔值,表示远程应用认证是否应该成为这个应用的默认认证方案。如果你传递的是true,那么在向任何没有指定不同认证方案的端点发出请求时,远程应用程序将默认查询用户的身份。这是全局启用远程应用程序认证的最简单的方法,但有一个缺点,即无论你是否需要使用用户的身份,都要对每个端点进行额外的HTTP请求。如果你为这个参数传递false,那么远程应用认证处理程序将被注册,但只用于特别请求远程应用认证方案的端点(通过在授权属性中指定方案,例如:[Authorize(AuthenticationSchemes = RemoteAppAuthenticationDefaults.AuthenticationScheme)] )。

传递给AddRemoteAppAuthentication 的第二个参数是用于配置RemoteAppAuthenticationOptions 的方法。在这个选项对象上必须设置的两个属性是:RemoteAppUrl ,这是认证请求应该被发送到的基本URL(我们可以从增量迁移工具已经设置的YARP配置中检索到,如上面的例子所示)和一个ApiKey 字符串,用于将ASP.NET Core应用认证为允许用远程应用认证用户的调用者。ApiKey 字符串可以是ASP.NET和ASP.NET Core应用程序之间安全共享的任何字符串。在本教程中,我们使用的是一个硬编码的字符串,但在现实世界的场景中,这应该是从应用程序的环境中安全加载的,甚至更好的是,像Azure Key Vault这样的安全存储。

我们还需要为ASP.NET Core应用程序启用认证中间件,因此在现有的对UseRouting 的调用之后,但在对UseAuthorization 的调用之前添加对app.UseAuthentication() 的调用。

现在,ASP.NET Core应用程序被设置为查询ASP.NET应用程序的认证,我们需要配置ASP.NET应用程序,使其能够响应这些请求。导航到ASP.NET应用程序的global.asax.cs文件,在Application_Start 方法的末尾添加以下调用:

Application.AddSystemWebAdapters()
    .AddRemoteAppAuthentication(options =>
        options.RemoteServiceOptions.ApiKey = "test-key");

你还需要在global.asax.cs的顶部添加一个导入语句using Microsoft.AspNetCore.SystemWebAdapters; 。这段代码看起来应该很熟悉。与在ASP.NET Core应用程序中注册认证处理程序的代码类似,这个调用是在ASP.NET应用程序中配置一个HTTP处理程序来处理认证请求。这里唯一需要的选项是ApiKey 属性,当然,它必须与ASP.NET Core应用程序中使用的API密钥相匹配。

添加一个测试页面

在这一点上,远程应用程序认证的配置是这样的:ASP.NET Core应用程序将看到登录到ASP.NET应用程序的用户的身份,如果ASP.NET Core应用程序挑战认证,它应该重定向到ASP.NET应用程序的登录页面。不过,为了测试这一点,我们需要一个利用用户身份的ASP.NET Core端点。

首先,将ASP.NET Core应用程序的Program.cs中对app.MapControllers(); 的调用替换为对MapDefaultControllerRoute 的调用,这样我们就可以很容易地路由到ASP.NET Core控制器。

app.MapDefaultControllerRoute();

接下来,在ASP.NET Core应用程序中添加一个Controllers文件夹,并创建一个简单的控制器,名为UserInfoController ,有一个Index动作方法:

using Microsoft.AspNetCore.Mvc;

namespace MigrationDemoCore.Controllers;

public class UserInfoController : Controller
{
    [Authorize]
    public IActionResult Index()
    {
        return View();
    }
}

最后为控制器的索引端点创建一个视图,行使User.Identity 。在项目中创建一个名为Views的文件夹。在这个文件夹中,创建一个名为UserInfo的文件夹。最后创建一个名为Index.cshtml的视图,内容与此类似:

<h1>User Info</h1>
<h2>@(User.Identity?.Name??"Anonymous user")</h2>
<h3>Claims</h3>
<ul>
@foreach(var c in User.Claims)
{
    <li>@c.Type: @c.Value</li>
}
</ul>

有了这些,我们就可以启动示例应用程序,看到它从头到尾都在工作。该应用程序的大部分端点仍然由原来的ASP.NET应用程序提供服务。但如果你导航到/UserInfo 路由,该端点就由ASP.NET Core应用程序提供服务。因为该端点受到[Authorize] 属性的保护,所以当未认证的用户试图访问该端点时,他们将被重定向到该应用的登录页面。对于已认证的用户,尽管/UserInfo 是由ASP.NET Core应用程序提供的,你可以看到用户的身份(由ASP.NET应用程序提供)是可用的:

User identity provided by ASP.NET, used in ASP.NET Core

请注意,即使你从/UserInfo 删除了[Authorize] 属性,如果有用户登录,端点仍然可以访问用户的身份。如果没有经过认证的用户,User.Identity 将为空。

总结

在这个增量ASP.NET迁移工具的第二个预览版中,增加了许多新的功能--最值得一提的是在增量升级方案中,在ASP.NET和ASP.NET Core应用程序之间共享认证的能力。使用这一功能,开发人员应该能够逐步将端点从现有的ASP.NET应用程序转移到新的ASP.NET Core应用程序中,即使这些端点需要对用户进行认证。

目前的共享认证解决方案是一个通用的解决方案,应该适用于大多数类型的认证,但我们正在继续研究其他的远程认证选项,这些选项可能对特定类型的认证更加有效或高效。我们还在探索共享认证,通过集中所有的认证决定,由ASP.NET核心应用程序(而不是ASP.NET应用程序)来实现。将该功能与Preview 2中已有的功能相结合,可以让开发者立即开始将端点转移到ASP.NET Core,但在迁移过程中的某个时间点将认证责任转移到ASP.NET Core应用。

除了共享认证工作外,我们还在继续扩大System.Web适配器的面积,以包括System.Web中更多最常用的API。

如果你对该工具有任何反馈,无论是错误报告还是功能建议,你都可以在GitHub上通过创建问题或拉动请求来为该项目做出贡献。