多ASP.Net MVC Core应用共享凭证实现单点登录的最简方案咨询
嘿,针对你这种部署在同一服务器、面向外部客户的多ASP.NET Core MVC应用实现单点登录(SSO)的需求,结合你不想折腾复杂OAuth服务器的诉求,我来梳理下最适合的方案,还有补充几个你没提到的可行选项:
优先推荐:共享认证Cookie(同域名场景)
这绝对是你当前场景下最简、成本最低的方案,前提是你的所有应用都在同一主域名下(比如app1.yourdomain.com、app2.yourdomain.com)。核心思路是让所有应用使用相同的认证Cookie配置,并且共享数据保护密钥(ASP.NET Core用它加密Cookie,不同应用密钥不同的话,其他应用解不开Cookie)。
具体配置步骤:
- 共享数据保护密钥:在每个应用的
Program.cs里配置数据保护,将密钥存储在服务器的同一个目录(因为是同一服务器,本地目录就行),并且设置相同的应用名称:
builder.Services.AddDataProtection() .PersistKeysToFileSystem(new DirectoryInfo(@"C:\SharedAuthKeys")) .SetApplicationName("YourGlobalAppName"); // 所有应用用同一个名称
- 统一Cookie认证配置:每个应用的认证中间件使用相同的Cookie名称、域名和认证方案:
builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme) .AddCookie(options => { options.Cookie.Name = ".YourSharedAuthCookie"; // 所有应用用同一个Cookie名 options.Cookie.Domain = ".yourdomain.com"; // 顶级域名,让子域名都能识别 // 其他通用配置,比如登录路径、过期时间等,保持一致 });
这样用户登录任意一个应用后,其他应用都会识别到这个Cookie,直接实现免登录访问,完全不用额外开发业务逻辑。
次选:共享MS Identity认证数据库 + 配合Cookie共享
你提到的共用认证数据库方案,本身只是统一了用户数据(所有应用用同一个AspNetUsers等表),但如果不配合Cookie共享,用户还是需要在每个应用单独登录。所以如果想用这个方案,一定要和上面的Cookie共享配置结合——既统一用户数据,又实现单点登录。
这个方案适合需要统一用户管理(比如同一个用户在所有应用里的身份一致),同时又要SSO的场景,配置成本也很低,只需要把每个应用的Identity数据库连接指向同一个库,再加上Cookie和数据保护的统一配置就行。
补充方案:用现有应用做简易OIDC认证中心(适合跨域名场景)
如果你的应用不在同一域名下,或者不想用Cookie共享,那可以选其中一个现有应用作为简易认证中心,其他应用作为OIDC客户端,不用部署独立的Identity Server,实现成本比Identity Server低很多。
核心思路:
- 改造其中一个应用,启用OpenID Connect(OIDC)服务端功能,作为用户的统一登录入口
- 其他应用配置为OIDC客户端,用户访问时自动跳转到认证中心登录,登录成功后返回身份凭证
简单配置示例:
认证中心应用(Program.cs):
// 先确保已经配置了Identity数据库 builder.Services.AddDbContext<ApplicationDbContext>(options => { options.UseSqlServer(builder.Configuration.GetConnectionString("IdentityDB")); options.UseOpenIddict(); }); // 添加OpenIddict服务端支持 builder.Services.AddOpenIddict() .AddCore(options => { options.UseEntityFrameworkCore().UseDbContext<ApplicationDbContext>(); }) .AddServer(options => { // 配置OIDC端点 options.SetAuthorizationEndpointUris("/connect/authorize") .SetLogoutEndpointUris("/connect/logout") .SetTokenEndpointUris("/connect/token"); // 启用授权码流程(适合Web应用) options.AllowAuthorizationCodeFlow(); options.AllowRefreshTokenFlow(); // 开发环境用自动生成的证书,生产环境用正式证书 options.AddDevelopmentEncryptionCertificate() .AddDevelopmentSigningCertificate(); // 集成ASP.NET Core管道 options.UseAspNetCore() .EnableAuthorizationEndpointPassthrough() .EnableLogoutEndpointPassthrough(); });
客户端应用(Program.cs):
builder.Services.AddAuthentication(options => { options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme; options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme; }) .AddCookie() .AddOpenIdConnect(options => { options.Authority = "https://your-auth-center-app.com"; // 认证中心的地址 options.ClientId = "client-app-1"; // 给每个客户端分配唯一ID options.ClientSecret = "your-client-secret-key"; // 客户端密钥 options.ResponseType = "code"; options.Scope.Add("openid"); options.Scope.Add("profile"); // 获取用户基本信息 options.SaveTokens = true; // 保存令牌到Cookie });
这个方案符合标准的OIDC协议,扩展性也不错,而且不用额外部署服务器,非常适合不想搞Identity Server的场景。
不推荐的方案:单纯共享会话存储(比如Redis)
虽然可以把会话状态存在同一个Redis实例里,但这个方案需要额外处理登录状态的同步逻辑,而且每个应用的Cookie还是独立的,实现起来比上面的方案麻烦,性价比不高,除非有特殊需求,否则不推荐。
内容的提问来源于stack exchange,提问作者davewilliams459

