如何解决在 asp.net webforms 站点和 .net core 3.1 站点中使用相同的 cookie
我在同一个域上运行一个 asp.net Framework 4.8 webforms 项目和一个 asp.net core 3.1 项目,每个项目都有单独的子域。
我希望能够让用户在新站点上使用 .net 核心身份登录,这将为他们分配一个 cookie,并让该 cookie 在使用 Owin 中间件的旧网络表单应用程序上对他们进行身份验证。
根据我所做的研究,使用 webforms 身份验证和 .net core 似乎不可能做到这一点。但是,是否可以使用 microsoft.aspnet.identity 和 Owin 中间件?我是否可以使用 Owin 中间件以某种方式解密 webforms 站点上的 .net 核心 cookie 并使用它的声明为 webforms 站点设置 aspnet.identity cookie,或者只是将这些声明注入旧应用程序,以便我可以拥有我的 HttpContext 用户身份认为应用程序?
据说 John Geddes 找到了解决方案,但没有时间分享他的做法(请参阅他对此 answer 的评论)。他说他在 .net framework webforms 应用程序上使用了 Owin,但没有提供更多细节。
这是我的.net core启动类
public class Startup
{
public IConfiguration Configuration { get; }
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddIdentity<User,IdentityRole>(cfg =>
{
cfg.User.RequireUniqueEmail = true;
})
.AddEntityFrameworkStores<SJRContext>()
.AddSignInManager<SJRSignInManager<User>>()
.AddDefaultTokenProviders()
.AddTokenProvider<CustomTwoFactorTokenProvider<User>>("TwoFactorAuthToken");
//cookie is added here
services.AddAuthentication()
.AddCookie(cfg =>
{
cfg.ExpireTimeSpan = TimeSpan.FromMinutes(20);
cfg.LoginPath = @"/Account/Login";
cfg.LogoutPath = @"/Account/Logout";
cfg.SlidingExpiration = true;
cfg.Cookie.Expiration = TimeSpan.FromMinutes(30);
cfg.Cookie.Domain = Configuration.GetSection("AppDomain").Value;
});
//More service set up here...
services.AddSession();
}
public void OnShutdown()
{
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app,IWebHostEnvironment env)
{
//More middleware here...
app.Use(async (ctx,next) =>
{
//Get and set cookie exp date according to ip address and client device here
//Go to next middleware
await next();
});
//More middleware here....
app.UseAuthorization();
}
}
这是在asp.net framework 4.8 webforms上设置cookie的Web.config
<system.web>
<authentication mode="Forms">
<!-- Set login to login page for development -->
<forms loginUrl="~/Account/Login.aspx" name=".AspNetCore.Identity.Application" enableCrossAppRedirects="true" cookieless="UseCookies" requireSSL="false" timeout="60" slidingExpiration="true" />
</authentication>
<authorization>
<deny users="?" />
<allow users="*" />
</authorization>
</system.web>
这是我的 web.release.config 文件,用于在发布模式下覆盖上述文件
<system.web>
<authentication mode="Forms">
<!-- Set login to .net core login page for production (Release)-->
<forms loginUrl="https://MyDotNetCoreSubDomain.SharedDomain.com/Account/Login" enableCrossAppRedirects="true" name=".AspNetCore.Identity.Application" cookieless="UseCookies" requireSSL="false" timeout="4320" domain=".SharedDomain.com" slidingExpiration="true" xdt:Transform="Replace"/>
</authentication>
</system.web>
解决方法
我能够通过这个 guide、这个 video 解决这个问题,并且通过其他研究对 cookie 的工作原理有所了解。我将概述完成这项工作的过程,以我的代码为例。
总结:简单地说,cookie 身份验证对 cookie(或使用 cookie 块的多个 cookie)上的主体(用户身份)进行加密,并将该 cookie 提供给客户端(用户)。每次客户端向服务器发出请求时,它们都会包含 cookie,服务器需要解密该 cookie。为了在多个 Web 应用程序中执行此操作,我们将加密密钥存储在两个应用程序都可以访问它并使用身份处理解密的地方。请注意,您需要保护此密钥,因为您的应用的安全性取决于它。
配置 .net core 3.1 站点的启动。这也适用于 .net core 2.x。
- 设置身份
services.AddIdentity<User,IdentityRole>(cfg =>
{
cfg.User.RequireUniqueEmail = true;
})
.AddEntityFrameworkStores<SJRContext>()
.AddSignInManager<SJRSignInManager<User>>()
.AddDefaultTokenProviders();
- 设置数据保护(使用该加密密钥)
services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(Configuration.GetSection("SharedCookie:CookieKeys").Value))
.SetApplicationName(Configuration.GetSection("SharedCookie:CookieApplicationName").Value);
- 设置 cookie(在我的例子中,我设置了 cookie 域并为每个网站使用了不同的子域)。
services.ConfigureApplicationCookie(opt =>
{
opt.Cookie.Name = Configuration.GetSection("SharedCookie:CookieName").Value;
opt.Cookie.Domain = Configuration.GetSection("AppDomain").Value;
opt.Cookie.Path = "/";
});
接下来,我需要配置我的旧 .net framework 4.8 webforms 站点以停止使用 webforms 身份验证并改用 owin 中间件。这样我就可以使用身份来解密共享的 cookie。
要做到这一点,我需要创建一个 Startup 类和 startup.auth 类 这 video 带我完成了这个。
- 这是我的入门课
Imports Microsoft.Owin
Imports Owin
<Assembly: OwinStartup(GetType(Startup))>
Partial Public Class Startup
Public Sub Configuration(ByVal app As IAppBuilder)
ConfigureAuth(app)
End Sub
End Class
注意这部分代码告诉owin使用它作为启动类:
<Assembly: OwinStartup(GetType(Startup))>
- 在我的 startup.auth 类中,我放置了所有身份验证逻辑。
这部分变得很复杂,很容易复制和粘贴,但不明白发生了什么。这部分过程在 Microsoft 演练 here 中进行了说明,但总而言之,您希望将两个站点的身份验证类型、cookie 名称、应用程序名称和密钥设置为相同。此外,请确保此 cookie 的登录和注销路径指向 .net core 登录和注销路径,以便可以将所有身份验证 cookie 分发到一个地方。
Imports System.IO
Imports Microsoft.AspNet.Identity.Owin
Imports Microsoft.AspNetCore.DataProtection
Imports Microsoft.Owin
Imports Microsoft.Owin.Security.Cookies
Imports Microsoft.Owin.Security.Interop
Imports Owin
Partial Public Class Startup
Public Sub ConfigureAuth(ByVal app As IAppBuilder)
app.UseCookieAuthentication(New CookieAuthenticationOptions With
{
.AuthenticationType = ConfigurationManager.AppSettings.Get("CookieAuthenticationType"),.CookieName = ConfigurationManager.AppSettings.Get("CookieName"),.LoginPath = New PathString(ConfigurationManager.AppSettings.Get("workordersWebAddress") + "Account/Login"),.LogoutPath = New PathString(ConfigurationManager.AppSettings.Get("workordersWebAddress") + "Account/Logout"),.Provider = New CookieAuthenticationProvider With
{
.OnValidateIdentity = SecurityStampValidator.OnValidateIdentity(Of ApplicationUserManager,ApplicationUser)(
validateInterval:=TimeSpan.FromMinutes(30),regenerateIdentity:=Function(manager,user) user.GenerateUserIdentityAsync(manager))
},.TicketDataFormat = New AspNetTicketDataFormat(
New DataProtectorShim(
DataProtectionProvider.Create(New DirectoryInfo(ConfigurationManager.AppSettings.Get("CookieKeys")),Function(builder) builder.SetApplicationName(ConfigurationManager.AppSettings.Get("CookieApplicationName"))
).CreateProtector(
"Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationMiddleware",ConfigurationManager.AppSettings.Get("CookieAuthenticationType"),"v2"
)
)
),.CookieManager = New ChunkingCookieManager()
})
End Sub
End Class
请注意,我使用的是 webforms 站点上的 web.config 文件和 appsettings.json 文件 在我的 .net core 站点上存储我的 cookie 名称、cookie 身份验证类型、cookie 密钥位置和应用程序名称。
在构建之前,您需要确保已安装所有 nuget 包,并且您已在 webforms 应用程序上正确设置了您的身份。我不打算在整个网络表单应用程序中使用身份和角色,因此我将向您展示如何使其仅适用于 cookie。
创建一个应用程序用户。注意我没有设置任何属性。我只是从 IdentityUser 对象继承属性。
Imports System.Security.Claims
Imports System.Threading.Tasks
Imports Microsoft.AspNet.Identity
Imports Microsoft.AspNet.Identity.EntityFramework
Public Class ApplicationUser
Inherits IdentityUser
Public Async Function GenerateUserIdentityAsync(ByVal manager As UserManager(Of ApplicationUser)) As Task(Of ClaimsIdentity)
' The authenticationType must match the one defined in
' CookieAuthenticationOptions.AuthenticationType
Dim userIdentity = Await manager.CreateIdentityAsync(Me,ConfigurationManager.AppSettings.Get("CookieName"))
' Add custom user claims here
Return userIdentity
End Function
End Class
接下来创建用户管理器。
Imports Microsoft.AspNet.Identity
Imports Microsoft.AspNet.Identity.EntityFramework
Imports Microsoft.AspNet.Identity.Owin
Imports Microsoft.Owin
Public Class ApplicationUserManager
Inherits UserManager(Of ApplicationUser)
Public Sub New(ByVal store As IUserStore(Of ApplicationUser))
MyBase.New(store)
End Sub
Public Shared Function Create(ByVal options As IdentityFactoryOptions(Of ApplicationUserManager),ByVal context As IOwinContext) As ApplicationUserManager
Dim store = New UserStore(Of ApplicationUser)(context.Get(Of WorkordersDatabase.SJContext)())
Dim manager = New ApplicationUserManager(store)
Return manager
End Function
End Class
在您的身份用户和用户管理器指向您的 .net 核心应用程序所指向的同一个 dbcontext 之后,您现在应该能够在两个站点上解密这些 cookie。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。