Asp.Net Core 3.1 基于同一Identity实例配置3个Web应用SSO及跨站角色
需求可行性
你提到的跨站SSO、统一角色权限覆盖3个站点的需求完全可以实现,和旧版.NET Membership的应用标识、目录级权限逻辑可以完全对齐,具体实现方案如下:
方案选型前置说明
如果你的3个站点属于同根域名(比如site1.xxx.com、site2.xxx.com、auth.xxx.com),优先用共享Cookie的轻量方案;如果是不同根域名,用基于OpenID Connect的统一身份提供商(IdP)方案即可。
方案1:同根域名共享Cookie实现SSO
步骤1:统一认证端配置
搭建独立的ASP.NET Core Identity站点作为统一认证入口,首先扩展Identity存储适配你的业务逻辑:
- 若要实现旧版Membership的应用ID访问控制,可新增
UserApplications关联表,存储用户ID与允许访问的应用ID映射关系 - 全局角色直接使用原生
AspNetRoles表存储即可,无需额外改造
然后配置Cookie与DataProtection:
// 注册Identity服务 builder.Services.AddIdentity<IdentityUser, IdentityRole>() .AddEntityFrameworkStores<AuthDbContext>() .AddDefaultTokenProviders(); // 配置共享Cookie builder.Services.ConfigureApplicationCookie(options => { options.Cookie.Name = ".UnifiedAuthCookie"; options.Cookie.Domain = ".yourdomain.com"; // 前缀带点,适配所有子域名 options.Cookie.HttpOnly = true; options.Cookie.SecurePolicy = CookieSecurePolicy.Always; options.LoginPath = "/Account/Login"; options.LogoutPath = "/Account/Logout"; }); // 配置统一的DataProtection密钥,所有站点必须一致 builder.Services.AddDataProtection() .PersistKeysToFileSystem(new DirectoryInfo(@"\\shared-storage\dp-keys")) // 存在所有站点都能访问的共享路径,也可以存在Redis、数据库中 .SetApplicationName("UnifiedAuthSystem"); // 所有站点的这个配置必须完全相同
步骤2:3个业务站点配置
所有业务站点无需部署独立的Identity体系,只需要配置相同的Cookie和DataProtection即可:
// 同认证端的DataProtection配置,完全一致 builder.Services.AddDataProtection() .PersistKeysToFileSystem(new DirectoryInfo(@"\\shared-storage\dp-keys")) .SetApplicationName("UnifiedAuthSystem"); // 配置认证方案,跳转统一认证端登录 builder.Services.AddAuthentication(IdentityConstants.ApplicationScheme) .AddCookie(IdentityConstants.ApplicationScheme, options => { options.Cookie.Name = ".UnifiedAuthCookie"; options.Cookie.Domain = ".yourdomain.com"; options.LoginPath = "https://auth.yourdomain.com/Account/Login"; options.LogoutPath = "https://auth.yourdomain.com/Account/Logout"; });
方案2:不同根域名场景
如果3个站点是完全不同的根域名,共享Cookie无法生效,直接在统一认证端集成OpenIddict或IdentityServer即可,两者都和ASP.NET Core Identity原生兼容:
- 3个站点作为OIDC客户端,所有登录、授权请求都跳转统一认证端处理
- 用户登录成功后,认证端会将用户角色、允许访问的应用ID等信息写入ID Token,业务站点解析Token即可拿到权限信息,无需单独存储用户、角色数据
统一角色权限实现逻辑
- 全局角色覆盖:认证端在用户登录成功后,将用户的所有角色写入Claims,业务站点直接使用原生的
[Authorize(Roles = "角色名")]特性即可做权限校验,无需单独维护角色数据 - 应用ID访问控制:认证端登录时校验当前请求的应用ID是否在用户允许的应用列表中,不在则直接拒绝授权;也可以将允许的应用ID列表写入Claims,业务站点可自行二次校验
- 目录/文件夹级权限:如果需要和旧版Membership一样做路径级权限控制,自定义授权策略即可,示例如下:
// 自定义路径权限校验规则 public class PathAccessRequirement : IAuthorizationRequirement { } public class PathAccessHandler : AuthorizationHandler<PathAccessRequirement> { protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, PathAccessRequirement requirement) { if (context.Resource is not HttpContext httpContext) return Task.CompletedTask; var currentRequestPath = httpContext.Request.Path.Value.ToLower(); // 从Claims中取当前用户被授权的所有路径前缀 var allowedPaths = context.User.Claims .Where(c => c.Type == "AllowedPath") .Select(c => c.Value.ToLower()) .ToList(); if (allowedPaths.Any(p => currentRequestPath.StartsWith(p))) { context.Succeed(requirement); } return Task.CompletedTask; } }
注册策略后直接用[Authorize(Policy = "PathAccess")]标记需要校验的控制器或Action即可。
注意事项
- 所有站点的DataProtection配置必须完全一致,否则无法互相解密认证信息
- 用户、角色、应用权限数据只需要在统一认证端维护,不需要同步到各个业务站点,避免数据不一致
- 统一退出登录时,需要先调用认证端的退出接口,再清除业务站点本地的认证Cookie
内容的提问来源于stack exchange,提问作者user307537
相关产品推荐
相关产品推荐

