You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET 6.0集成Azure AD SSO:如何无需存储用户直接依赖微软认证?

问题

我正在使用.NET 6.0,尝试通过微软登录服务实现SSO,不想自行管理用户(注册与存储)。我已在Azure门户创建应用,将重定向URI设置为https://localhost:7013/signin-oidc,注销URL设置为https://localhost:7013/signout-oidc。

appsettings.json中的配置:

"AzureAd": {
  "Instance": "https://login.microsoftonline.com",
  "TenantId": "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
  "ClientId": "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
  "CallbackPath": "/signin-oidc",
  "SignedOutCallbackPath": "/signout-oidc"
}

Program.cs中的代码:

builder.Services.AddAuthentication()
    .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"));

builder.Services.Configure<OpenIdConnectOptions>(OpenIdConnectDefaults.AuthenticationScheme,
    options => options.SignInScheme = IdentityConstants.ExternalScheme);

builder.Services.AddMvc(options =>
{
    var policy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build();
    options.Filters.Add(new AuthorizeFilter(policy));
}).AddMicrosoftIdentityUI();

随后我添加了脚手架生成的Identity项(Login、Logout和ExternalLogin),启动应用后点击OpenIdConnect按钮能正常跳转至微软登录页,但登录后返回需邮箱注册的页面,同时在ExternalLoginSignInAsync处触发InvalidOperationException,提示Cannot create a DbSet for 'IdentityUserLogin<string>' because this type is not included in the model for the context.

请问能否移除所有需注册存储用户的部分,完全依赖微软/Azure的认证?


解决方案

完全可以实现纯依赖微软认证、不存储本地用户的SSO,问题根源在于你引入了ASP.NET Core Identity组件,它强制要求本地数据库存储用户关联信息。按以下步骤修改:

1. 移除所有Identity相关内容

  • 删除脚手架生成的Areas/Identity文件夹
  • 卸载项目中所有Microsoft.AspNetCore.Identity.*系列的NuGet包
  • 移除appsettings.json中与Identity相关的配置(比如用于用户存储的ConnectionStrings)

2. 修改Program.cs配置

替换原有的认证相关代码,直接用微软身份认证结合Cookie存储身份,无需Identity:

using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.Identity.Web;

var builder = WebApplication.CreateBuilder(args);

// 添加微软身份认证,指定Cookie为登录凭证存储方案
builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"));

// 可选:自定义Cookie过期策略
builder.Services.Configure<CookieAuthenticationOptions>(CookieAuthenticationDefaults.AuthenticationScheme, options =>
{
    options.ExpireTimeSpan = TimeSpan.FromHours(8);
    options.SlidingExpiration = true;
});

// 全局授权策略:所有请求需登录后访问
builder.Services.AddControllersWithViews(options =>
{
    var policy = new AuthorizationPolicyBuilder()
        .RequireAuthenticatedUser()
        .Build();
    options.Filters.Add(new AuthorizeFilter(policy));
});

var app = builder.Build();

// 中间件顺序不能错:先认证再授权
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Home/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();

app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");

app.Run();

3. 自定义登录/注销逻辑(替代IdentityUI)

创建AccountController处理登录和注销请求:

using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Mvc;

public class AccountController : Controller
{
    // 触发微软登录流程
    public IActionResult SignIn()
    {
        var redirectUrl = Url.Action("Index", "Home");
        return Challenge(new AuthenticationProperties { RedirectUri = redirectUrl }, 
            OpenIdConnectDefaults.AuthenticationScheme);
    }

    // 注销:同时清除本地Cookie和微软会话
    public async Task<IActionResult> SignOut()
    {
        var redirectUrl = Url.Action("Index", "Home");
        await HttpContext.SignOutAsync(OpenIdConnectDefaults.AuthenticationScheme, 
            new AuthenticationProperties { RedirectUri = redirectUrl });
        await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
        return Redirect(redirectUrl);
    }
}

在视图(比如_Layout.cshtml)中添加登录/注销按钮:

@if (User.Identity.IsAuthenticated)
{
    <form asp-controller="Account" asp-action="SignOut" method="post" class="d-inline">
        <button type="submit" class="nav-link btn btn-link">注销 (@User.Identity.Name)</button>
    </form>
}
else
{
    <a asp-controller="Account" asp-action="SignIn" class="nav-link">登录</a>
}

关键说明

  • 原代码中options.SignInScheme = IdentityConstants.ExternalScheme是错误的,这个Scheme属于ASP.NET Core Identity,会强制关联本地用户;改用默认的Cookie认证方案后,直接用微软返回的身份信息生成本地Cookie,无需存储用户数据。
  • 移除AddMicrosoftIdentityUI(),这个组件是Identity的内置UI,会引导用户注册本地账户,不符合纯SSO的需求。

内容的提问来源于stack exchange,提问作者yyy-t

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 01:07:47