该 Microsoft.AspNetCore.SystemWebAdapters.Owin 库使 ASP.NET 核心应用程序能够在从 ASP.NET Framework 迁移期间使用 OWIN 中间件。 迁移依赖于基于 OWIN 的中间件的应用程序(尤其是身份验证、授权或自定义管道组件)时,此集成非常有用。
警告
使用 OWIN 集成时,可能需要禁止显示 .NET Framework 包依赖项的生成警告。 将以下内容添加到项目文件:
<PropertyGroup>
<NoWarn>$(NoWarn);NU1701</NoWarn>
</PropertyGroup>
只要使用的 API 存在并且具有相同的行为,就支持在 .NET Core 上运行 .NET Framework 代码。 建议将此用作迁移过程的一部分,但不要长时间处于此状态。
如果使用,某些包需要手动更新为受支持的版本。 这些包括:
- EntityFramework 必须为 >= 6.5.1,才能在 .NET Core 上获得最佳支持
为何使用 OWIN 集成
OWIN 集成在迁移过程中提供了多项优势:
- 保留现有中间件:在不立即重写的情况下从 ASP.NET Framework 应用程序中重复使用 OWIN 中间件
- 逐步迁移:在维护应用程序功能的同时以增量方式迁移中间件组件
- 身份验证连续性:在迁移期间维护身份验证状态并在 ASP.NET Framework 和 ASP.NET Core 应用程序之间共享 Cookie
- 熟悉的模式:继续使用团队已了解的 OWIN API 和模式
集成模式
该库提供三种不同的集成模式,每个模式都适合不同的迁移方案:
- OWIN 管道作为主管道中间件:将 OWIN 中间件直接添加到 ASP.NET 核心中间件管道
- OWIN 管道作为身份验证处理程序:使用 OWIN 中间件作为 ASP.NET 核心身份验证处理程序
-
模拟 HttpApplication 事件的 OWIN 管道:在模拟
HttpApplication管道中运行 OWIN 中间件
OWIN 管道作为中间件
此模式将 OWIN 中间件合并到 ASP.NET 核心中间件管道中,而无需使用模拟 HttpApplication 事件。
何时使用此模式
在以下情况下使用此方法:
- 你需要标准的中间件管道行为
- 应用程序不依赖于
HttpApplication事件 - 逐步将 OWIN 中间件迁移到 ASP.NET 核心模式
设置
将 OWIN 中间件添加到主管道:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.UseOwin(owinApp =>
{
owinApp.UseMyOwinMiddleware();
});
app.UseRouting();
app.MapControllers();
app.Run();
访问服务
配置 OWIN 中间件时访问服务:
app.UseOwin((owinApp, services) =>
{
var configuration = services.GetRequiredService<IConfiguration>();
owinApp.UseMyOwinMiddleware(configuration);
});
OWIN 身份验证处理程序
此模式使用 OWIN 中间件作为 ASP.NET 核心身份验证处理程序,与 AuthenticationBuilder API 集成。
何时使用此模式
在以下情况下使用此方法:
- 从 ASP.NET Framework 迁移身份验证逻辑
- 在 ASP.NET Framework 和 ASP.NET Core 应用程序之间共享身份验证 Cookie
- 使用 OWIN 身份验证中间件,例如 cookie 身份验证或 OAuth 提供程序
- 使用 ASP.NET Framework Identity
设置
将 OWIN 身份验证注册为 ASP.NET 核心身份验证处理程序:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddAuthentication()
.AddOwinAuthentication((owinApp, services) =>
{
owinApp.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Account/Login")
});
});
var app = builder.Build();
app.UseAuthentication();
app.UseAuthorization();
// Additional middleware or endpoint mapping
app.Run();
自定义身份验证方案
指定自定义身份验证方案名称:
builder.Services
.AddAuthentication()
.AddOwinAuthentication("MyOwinScheme", (owinApp, services) =>
{
owinApp.UseMyOwinAuthenticationMiddleware();
});
如果未提供方案名称,身份验证处理程序将用作 OwinAuthenticationDefaults.AuthenticationScheme 默认方案。 身份验证方案名称确定:
-
默认身份验证:如果设置为默认方案,则无需属性
[Authorize]即可自动对请求进行身份验证 - 质询行为:控制哪个处理程序响应身份验证挑战(例如重定向到登录页面)
-
身份验证选择:允许你显式地使用特定认证方案进行身份验证
HttpContext.AuthenticateAsync("scheme-name")
对于具有多个身份验证方案的应用程序,可以配置默认身份验证和质询方案:
builder.Services
.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = "MyOwinScheme";
options.DefaultChallengeScheme = "MyOwinScheme";
})
.AddOwinAuthentication("MyOwinScheme", (owinApp, services) =>
{
owinApp.UseMyOwinAuthenticationMiddleware();
});
有关身份验证方案以及如何在 ASP.NET Core 中工作的详细信息,请参阅 ASP.NET 核心身份验证和使用cookie身份验证概述,而无需 ASP.NET 核心Identity。
访问 OWIN 身份验证
继续使用 OWIN IAuthenticationManager 接口:
var authManager = HttpContext.GetOwinContext().Authentication;
authManager.SignIn(identity);
authManager.SignOut();
ClaimsPrincipal.Current
如果代码需要使用 ClaimsPrincipal.Current,请参阅 “从静态 ClaimsPrincipal 访问迁移 ”以获取启用该属性设置的选项。
迁移 ASP.NET 框架 Identity
常见的迁移方案涉及 ASP.NET 框架Identity与 OWIN cookie身份验证。 此示例演示如何在迁移期间保持兼容性。
配置数据保护
配置数据保护,以便与 ASP.NET 框架设置 cookie 的共享相匹配:
var builder = WebApplication.CreateBuilder(args);
var sharedApplicationName = "CommonMvcAppName";
builder.Services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(Path.Combine(Path.GetTempPath(), "sharedkeys", sharedApplicationName)))
.SetApplicationName(sharedApplicationName);
配置 OWIN 身份验证
使用 Identity 服务设置 OWIN 身份验证:
builder.Services
.AddAuthentication()
.AddOwinAuthentication("AppAuthenticationScheme", (app, services) =>
{
app.CreatePerOwinContext(ApplicationDbContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);
var dataProtector = services.GetDataProtector(
"Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationMiddleware",
"AppAuthenticationScheme",
"v2");
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Account/Login"),
Provider = new CookieAuthenticationProvider
{
OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
validateInterval: TimeSpan.FromMinutes(30),
regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
},
CookieName = ".AspNet.ApplicationCookie",
TicketDataFormat = new AspNetTicketDataFormat(new DataProtectorShim(dataProtector))
});
});
在控制器中使用
在控制器中访问 OWIN 注册的服务:
using Microsoft.AspNet.Identity.Owin;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.SystemWebAdapters;
using Microsoft.Owin.Security;
[Authorize]
public class AccountController : Controller
{
public ApplicationSignInManager SignInManager =>
HttpContext.GetOwinContext().Get<ApplicationSignInManager>();
public ApplicationUserManager UserManager =>
HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
private IAuthenticationManager AuthenticationManager =>
HttpContext.GetOwinContext().Authentication;
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Login(LoginViewModel model)
{
var result = await SignInManager.PasswordSignInAsync(
model.Email,
model.Password,
model.RememberMe,
shouldLockout: false);
if (result == SignInStatus.Success)
{
return RedirectToAction("Index", "Home");
}
ModelState.AddModelError("", "Invalid login attempt.");
return View(model);
}
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Logout()
{
AuthenticationManager.SignOut(DefaultAuthenticationTypes.ApplicationCookie);
return RedirectToAction("Index", "Home");
}
}
关键配置点
迁移 ASP.NET 框架 Identity时:
-
数据保护:在 ASP.NET Framework 和 ASP.NET Core 中配置相同
ApplicationName和密钥存储位置 -
按请求服务:用于
app.CreatePerOwinContext<T>()注册每个请求创建一次的服务 - 数据保护网桥:使用
AspNetTicketDataFormatDataProtectorShim将 ASP.NET Core 的IDataProtector桥接到 OWIN -
服务访问:通过
HttpContext.GetOwinContext()访问 OWIN 注册的服务 -
Cookie 名称:确保
CookieName共享身份验证状态时应用程序之间的匹配项
HttpApplication 事件中的 OWIN 管道
此模式在模拟 HttpApplication 事件管道中运行 OWIN 中间件,类似于 OWIN 在 ASP.NET Framework 的集成管道模式下的工作方式。
何时使用此模式
在以下情况下使用此方法:
- 应用程序依赖于 ASP.NET Framework 集成管道
- OWIN 中间件需要在特定
HttpApplication事件阶段执行 - 你正在迁移使用
HttpApplication事件和OWIN的应用程序
设置
在 HttpApplication 事件中配置运行 OWIN 管道:
var builder = WebApplication.CreateBuilder(args);
builder.Services
.AddSystemWebAdapters()
.AddOwinApp(app =>
{
app.UseMyOwinMiddleware();
app.UseStageMarker(PipelineStage.Authenticate);
});
var app = builder.Build();
app.UseSystemWebAdapters();
app.Run();
访问服务
在配置 OWIN 管道时访问 IServiceProvider。
builder.Services
.AddSystemWebAdapters()
.AddOwinApp((app, services) =>
{
var configuration = services.GetRequiredService<IConfiguration>();
app.UseMyOwinMiddleware(configuration);
app.UseStageMarker(PipelineStage.Authenticate);
});
HttpApplication 事件映射
OWIN 管道与以下 HttpApplication 事件集成:
AuthenticateRequest/PostAuthenticateRequestAuthorizeRequest/PostAuthorizeRequestResolveRequestCache/PostResolveRequestCacheMapRequestHandler/PostMapRequestHandlerAcquireRequestState/PostAcquireRequestStatePreRequestHandlerExecute
使用 .UseStageMarker(PipelineStage) 控制 OWIN 中间件相对于这些事件的执行顺序。
迁移策略
将 OWIN 中间件合并到 ASP.NET Core 应用程序中时:
- 确定 OWIN 依赖项:确定应用程序使用的 OWIN 中间件
- 选择集成模式:根据应用程序的需求选择适当的模式
- 配置数据保护:为身份验证 cookie 共享设置共享数据保护
- 测试身份验证流:验证身份验证在 ASP.NET Core 应用程序中正常工作
- 逐步转换:计划随着时间的推移将 OWIN 中间件迁移到本机 ASP.NET 核心中间件
- 监视兼容性:确保 OWIN 中间件行为在迁移过程中符合预期