.Net Core 3中UseOpenIdConnectAuthentication等效用法及声明添加
解答
问题1:.NET Core 3中UseOpenIdConnectAuthentication的等效实现
ASP.NET Core 3 没有和.NET Framework 4同名的UseOpenIdConnectAuthentication扩展方法,对应能力通过OpenID Connect认证服务+事件回调实现,执行时机和原有逻辑完全一致:
- 首先通过NuGet安装
Microsoft.AspNetCore.Authentication.OpenIdConnect包 - 在
Startup.ConfigureServices中先注册Cookie认证作为本地会话持久化方案,再注册OpenID Connect认证,和你原有先配置Cookie、再配置OIDC的顺序一致 - 原有代码里
SecurityTokenValidated通知的等效逻辑,写在OIDC配置的Events节点下的OnTokenValidated委托中即可,这个委托会在AAD返回的安全令牌校验通过、用户身份初步构建完成后立刻触发,正好适合做用户数据拉取、权限初始化这类操作 - 原有
AuthenticationFailed通知对应OnAuthenticationFailed委托,逻辑可以直接迁移 - 最后在
Startup.Configure中按顺序调用app.UseAuthentication()、app.UseAuthorization()即可,不需要单独注册Use开头的OIDC中间件。
问题2:基于已认证身份添加自定义声明
自定义声明的逻辑直接放在上面提到的OnTokenValidated事件中处理即可,操作流程:
- 从事件参数的
Principal属性拿到AAD返回的已认证用户身份,提取用户唯一标识(一般用AAD返回的oid声明,也就是用户对象ID) - 用这个唯一标识查询你自己维护的用户、角色数据表,拿到对应用户的角色、权限、业务属性数据
- 从用户身份中拿到
ClaimsIdentity实例,调用AddClaim方法把查询到的角色、权限等自定义声明逐个添加进去 - 事件执行完成后,这些声明会被自动加密写入本地认证Cookie,后续请求会自动携带,不需要重复查询数据库。
参考实现代码
// Startup.cs ConfigureServices 方法配置 public void ConfigureServices(IServiceCollection services) { // 其余业务服务注册逻辑保持原有即可 services.AddAuthentication(options => { options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme; options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme; }) .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options => { // 此处可配置Cookie过期时间、登录跳转路径等规则,和.NET4中Cookie配置逻辑一致 }) .AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, options => { options.ClientId = "替换为你的AAD应用ClientId"; options.Authority = "替换为你的AAD实例地址"; options.CallbackPath = "/signin-oidc"; // 对应原有配置中的RedirectUri路径 // 其余AAD对接参数按实际场景补充即可 options.Events = new OpenIdConnectEvents { // 对应原有AuthenticationFailed逻辑 OnAuthenticationFailed = context => { context.Response.Redirect("/Home/Error"); context.HandleResponse(); return Task.CompletedTask; }, // 对应原有SecurityTokenValidated逻辑:令牌校验通过后执行 OnTokenValidated = async context => { var claimsIdentity = (ClaimsIdentity)context.Principal.Identity; // 提取AAD返回的用户唯一标识 var userAadId = claimsIdentity.FindFirstValue("http://schemas.microsoft.com/identity/claims/objectidentifier"); // 查询本地用户、角色数据,替换成你自己的DbContext即可 var dbContext = context.HttpContext.RequestServices.GetRequiredService<YourAppDbContext>(); var appUser = await dbContext.Users.FirstOrDefaultAsync(u => u.AadObjectId == userAadId); if (appUser == null) { // 本地无对应用户时可按需求做自动注册或拒绝访问处理 context.Response.Redirect("/Account/AccessDenied"); context.HandleResponse(); return; } // 添加自定义声明 claimsIdentity.AddClaim(new Claim(ClaimTypes.Name, appUser.DisplayName)); // 批量添加角色声明 var userRoles = await dbContext.UserRoles .Where(r => r.UserId == appUser.Id) .Select(r => r.RoleCode) .ToListAsync(); foreach (var role in userRoles) { claimsIdentity.AddClaim(new Claim(ClaimTypes.Role, role)); } // 其余业务声明按相同方式添加即可 } }; }); services.AddControllersWithViews(); } // Startup.cs Configure 方法配置 public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { // 其余中间件配置保持原有即可 app.UseStaticFiles(); app.UseRouting(); // 注意认证、授权中间件顺序不能调换 app.UseAuthentication(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); }); }
注意:如果你的自定义声明数据量较大,不要全部存在Cookie中,避免超过浏览器单Cookie大小限制。这种场景可以只在Cookie中存储用户ID,后续通过
IClaimsTransformation接口或者自定义中间件动态加载权限声明即可。
内容的提问来源于stack exchange,提问作者Jerry
相关产品推荐
相关产品推荐

