ASP.NET Core 3.1 同时使用 OpenIDConnect 和自定义 Cookie 身份验证

ASP.NET Core 3.1 Use both OpenIDConnect and Custom Cookie Authentication

我有一个使用 Cookie Authentication 的现有应用程序,我想添加使用 Active Directory 对用户进行身份验证的功能。当前应用程序使用基于 Cookie authentication 和自定义 authorisation - 数据库中的角色。

我正在从位于此处的示例添加位:

Add sign-in with Microsoft to an ASP.NET Core web app

当我 运行 应用程序出现错误时:

System.InvalidOperationException: Scheme already exists: Cookies

配置 OpenIdConnectCookie Authentication 的正确方法是什么。

// 第 1 步基本 Cookie 验证

services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
        .AddCookie(options =>
            {
                options.LoginPath = "/Auth";
                options.AccessDeniedPath = "/Home/AccessDenied";
                options.Cookie.IsEssential = true;
                options.SlidingExpiration = true;
                options.ExpireTimeSpan = TimeSpan.FromSeconds(day/2.0);
                options.Cookie.HttpOnly = true; // not accessible via JavaScript
                options.Cookie.Name = "login_token";

                options.TicketDataFormat = new CustomJwtDataFormat(
                    SecurityAlgorithms.HmacSha256,
                    tokenValidationParameters);
            });

// 步骤 2 OpenID 连接验证

services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
        .AddMicrosoftIdentityWebApp(Configuration.GetSection("AzureAd"), "OpenIdConnect", "Cookies", true);

我无法找到同时使用 Cookie AuthenticationOpenID Connect 的任何示例。这可能吗? 允许用户有选择地使用 Active Directory 身份验证或本地身份验证(详细信息存储在本地数据库中)登录。

更改“Cookie”名称后,去掉错误信息, 但破坏了本地授权,例如

当给出有效的用户名和密码时,我通常 授权登录。

HttpContext.Response.Cookies.Append("login_token", token, GetCookieOptions());

当前配置了 OpenIDConnect User.Identity.IsAuthenticated 仍然是假的。

根据错误信息,它告诉你你有多个名为cookies的Scheme。

根据AddMicrosoftIdentityWebApp方法document,可以发现第三个参数名称是cookieScheme。

要使用的基于 cookie 的方案名称。默认情况下它使用“Cookies”。

但是你已经在上面设置了这个名字,所以你应该使用其他的。例如:“ADCookies”。

如下所示:

services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
        .AddMicrosoftIdentityWebApp(Configuration.GetSection("AzureAd"), "OpenIdConnect", "ADCookies", true);

可以混合使用两种机制。 我使用 MicrosoftIdentity 身份验证来访问我的 APIs 和 SignalR 中心的管理网页和 cookie 身份验证。

我在启动 ConfigureServices 时使用它

services
    .AddAuthentication(sharedOptions =>
    {
        sharedOptions.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        sharedOptions.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
        sharedOptions.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    })
    .AddCookie("CookiesApiScheme", options =>
    {
        options.SlidingExpiration = true;
        // There is no redirection to a login page for APIs and SignalR Hubs, I just made a call to /Api/Login/SignIn with credential
        options.AccessDeniedPath = new PathString("/Api/Login/AccessDenied"); // Action who just returns an Unauthorized
    })
    .AddMicrosoftIdentityWebApp(Configuration); // By default scheme is "CookieAuthenticationDefaults.AuthenticationScheme"

并且在 API 控制器中你可以使用这样的东西

    [Route("api/[controller]")]
    [ApiController]
    [Authorize(Roles = Roles.ADMIN)]
    [Authorize(AuthenticationSchemes = "CookiesApiScheme")]
    public class DefaultController : ControllerBase
    {
        [HttpGet]
        public IEnumerable<string> Get()
        {
            return new string[] { "value1", "value2" };
        }
    }

基于此post:

混合方法是一个雷区,但下面允许使用 OIDC 通过 IdentityServer4 对用户进行身份验证,同时使用 Identity.Web 将应用程序验证到 AzureAD 以获取 Api 调用的令牌。

services.AddAuthentication(options =>
{
    options.DefaultScheme = "IS4Cookies";
    options.DefaultChallengeScheme = "oidc";
})
.AddCookie("IS4Cookies")
.AddOpenIdConnect("oidc", "OpenID Connect", options =>
{
    options.SignInScheme = "IS4Cookies";
    // Get IdentityServer configuration from appsettings.json.
    var config = Configuration.GetSection("IdentityServerOptions").Get<IdentityServerOptions>();

    options.Authority = config.Authority;
    options.RequireHttpsMetadata = false;
    options.ClientId = config.ClientId;
    options.ClientSecret = config.ClientSecret;
    options.ResponseType = "code";
    options.SaveTokens = true;
    options.GetClaimsFromUserInfoEndpoint = true;
    options.ClaimActions.MapJsonKey("role", "role");
    options.ClaimActions.MapJsonKey("role", System.Security.Claims.ClaimTypes.Role);
    options.ClaimActions.MapJsonKey("email", "email");
    options.ClaimActions.MapJsonKey("preferred_username", "preferred_username");
    options.Events = new OpenIdConnectEvents
    {
        OnRemoteFailure = context =>
        {
            context.Response.Redirect("/");
            context.HandleResponse();
            return Task.FromResult(0);
        }
    };
})
.AddMicrosoftIdentityWebApp(Configuration, "AzureOptions")
    .EnableTokenAcquisitionToCallDownstreamApi(new string[]{"sms.all" })
    .AddInMemoryTokenCaches();