如何结合ASP.NET Identity与Sustainsys库实现Azure AD SAML2单点登录?
使用Sustainsys.SAML2结合ASP.NET Identity实现Azure AD SSO
以下是完整的集成步骤与代码示例:
1. 安装必要的NuGet包
在项目中安装依赖包:
Install-Package Sustainsys.Saml2.AspNetCore2 Install-Package Microsoft.AspNetCore.Identity.EntityFrameworkCore
2. 准备Azure AD SAML配置
在Azure门户完成基础配置:
- 创建企业应用程序,启用SAML单点登录
- 记录Azure AD标识符(即SAML实体ID)和SAML元数据URL
- 设置回复URL(ACS URL)为你的应用地址 +
/saml2/acs(例如:https://your-app.com/saml2/acs)
3. 配置服务与中间件(Program.cs)
注册Identity与SAML服务
var builder = WebApplication.CreateBuilder(args); // 注册Identity服务 builder.Services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection"))); builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true) .AddEntityFrameworkStores<ApplicationDbContext>(); // 配置Sustainsys.SAML2 builder.Services.AddSaml2(options => { // 设置应用自身的SAML实体ID options.SPOptions.EntityId = new EntityId("https://your-app.com"); // 添加Azure AD作为身份提供商 options.IdentityProviders.Add(new IdentityProvider( new EntityId("https://sts.windows.net/your-tenant-id/"), // Azure AD标识符 options.SPOptions) { MetadataLocation = "https://login.microsoftonline.com/your-tenant-id/federationmetadata/2007-06/federationmetadata.xml", // Azure AD元数据URL LoadMetadata = true }); // 映射SAML声明到Identity标准声明 options.ClaimTypeMap[ClaimTypes.Email] = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"; options.ClaimTypeMap[ClaimTypes.Name] = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name"; }); var app = builder.Build(); // 配置中间件顺序 app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); app.UseAuthentication(); app.UseSaml2(); // 必须放在UseAuthentication之后、UseAuthorization之前 app.UseAuthorization(); app.MapRazorPages(); app.MapControllers(); app.Run();
4. 添加SAML登录入口
在登录页面(如Login.cshtml)中,添加Azure AD SSO登录按钮:
<form asp-action="Login" method="post"> <!-- 原有密码登录表单 --> <div class="form-group"> <label asp-for="Email"></label> <input asp-for="Email" class="form-control" /> </div> <div class="form-group"> <label asp-for="Password"></label> <input asp-for="Password" class="form-control" type="password" /> </div> <div class="form-group"> <input asp-for="RememberMe" /> <label asp-for="RememberMe"></label> </div> <button type="submit" class="btn btn-primary">密码登录</button> </form> <!-- SAML登录按钮 --> <a href="/saml2/signin" class="btn btn-secondary mt-2">Azure AD SSO登录</a>
5. 处理SAML回调与Identity用户关联
在AccountController中添加外部登录回调逻辑,将SAML认证用户关联到Identity系统:
[HttpGet] public async Task<IActionResult> ExternalLoginCallback(string returnUrl = null, string remoteError = null) { if (remoteError != null) { ModelState.AddModelError(string.Empty, $"外部提供商错误: {remoteError}"); return View("Login"); } var loginInfo = await _signInManager.GetExternalLoginInfoAsync(); if (loginInfo == null) { return RedirectToAction(nameof(Login)); } // 尝试用外部登录信息直接登录 var signInResult = await _signInManager.ExternalLoginSignInAsync( loginInfo.LoginProvider, loginInfo.ProviderKey, isPersistent: false, bypassTwoFactor: true); if (signInResult.Succeeded) { return LocalRedirect(returnUrl ?? Url.Content("~/")); } // 若用户不存在,创建新用户并关联外部登录 var email = loginInfo.Principal.FindFirstValue(ClaimTypes.Email); var newUser = new IdentityUser { UserName = email, Email = email }; var createResult = await _userManager.CreateAsync(newUser); if (createResult.Succeeded) { createResult = await _userManager.AddLoginAsync(newUser, loginInfo); if (createResult.Succeeded) { await _signInManager.SignInAsync(newUser, isPersistent: false); return LocalRedirect(returnUrl ?? Url.Content("~/")); } } foreach (var error in createResult.Errors) { ModelState.AddModelError(string.Empty, error.Description); } return View("Login"); }
现有密码登录代码兼容
你原有的密码登录逻辑无需修改,可与SAML SSO登录共存:
var result = await _signInManager.PasswordSignInAsync(Input.Email, Input.Password, Input.RememberMe, lockoutOnFailure: true); if (result.Succeeded) { return LocalRedirect(returnUrl ?? Url.Content("~/")); }
内容的提问来源于stack exchange,提问作者Nani
相关产品推荐
相关产品推荐

