使用多个授权提供者-Cookie身份验证和Open ID Connect

时间:2020-04-03 21:04:28

标签: openid-connect .net-core-3.1

我正在尝试使用多个身份验证提供程序-一个非常简单的cookie身份验证,并打开了id连接。我的大多数用户将使用简单的cookie身份验证。但是,一些用户已经在开放ID连接系统上,我希望他们能够连接。我可以使其中一个工作,但不能同时工作。添加openid connect会覆盖其他cookie系统。我怎样才能使它们彼此和谐地玩耍。可以接受的解决方案是,Open ID连接不重定向到登录屏幕,而用户将需要手动登录。

这是我的启动班:

public class Startup
{
    public Startup(IConfiguration configuration) => this.Configuration = configuration;

    public IConfiguration Configuration { get; }

    private CultureInfo[] supportedCultures;
    private CultureInfo[] SupportedCultures => this.supportedCultures ??= new[] { new CultureInfo("en-US") };

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddRouting(options =>
        {
            options.LowercaseUrls = true;
            options.AppendTrailingSlash = false;
            options.LowercaseQueryStrings = true;
        });

        // Add MVC with feature folders
        services.AddMvc(opt => opt.Filters
            .Add(typeof(DbContextTransactionFilter)))
            .AddFeatureFolders()
            .AddViewLocalization()
            .AddDataAnnotationsLocalization();

        // Add HTTP Context to DI Container
        services.AddHttpContextAccessor();

        // Add localization
        services.AddLocalization();
        services.Configure<RequestLocalizationOptions>(options =>
        {
            // Just supporting English right now
            options.DefaultRequestCulture = new RequestCulture("en-US", "en-US");

            // You must explicitly state which cultures your application supports.
            // These are the cultures the app supports for formatting 
            // numbers, dates, etc.
            options.SupportedCultures = this.SupportedCultures;

            // These are the cultures the app supports for UI strings, 
            // i.e. we have localized resources for.
            options.SupportedUICultures = this.SupportedCultures;
        });

        services.Configure<CookiePolicyOptions>(options =>
        {
            options.CheckConsentNeeded = context => true;
            options.MinimumSameSitePolicy = SameSiteMode.None;
        });

        services.AddAuthentication(options =>
            {
                options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme = "oidc";
            })
            .AddCookie(options =>
            {
                options.AccessDeniedPath = "/request-access";
                options.ExpireTimeSpan = TimeSpan.FromDays(14);
                options.LoginPath = "/request-access";
                options.LogoutPath = "/request-access";
                options.Cookie.Name = "AMGAuthCookie";
            })
            .AddOpenIdConnect("oidc", options =>
            {
                options.ClientId = "MyClientID";
                options.Authority = "https://myidentityserver.com/";
                options.RequireHttpsMetadata = false;
                options.GetClaimsFromUserInfoEndpoint = true;
                options.ResponseType = "code token";

                options.Scope.Clear();
                options.Scope.Add("openid");
                options.Scope.Add("sitecore.profile");
                options.Scope.Add("offline_access");
                options.Scope.Add("sitecore.profile.api");

                options.SaveTokens = true;

                options.TokenValidationParameters = new TokenValidationParameters
                {
                    NameClaimType = JwtClaimTypes.Name,
                    RoleClaimType = JwtClaimTypes.Role,
                };
            }); 
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        var pageOptions = new DeveloperExceptionPageOptions { SourceCodeLineCount = 10 };
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage(pageOptions);
        }
        else
        {
            app.UseStatusCodePagesWithReExecute("/error/{0}");
            // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
            app.UseHsts();
        }
        app.UseHttpsRedirection();
        app.UseStaticFiles();

        app.UseRouting();

        app.UseAuthentication();
        app.UseAuthorization();

        var cookiePolicyOptions = new CookiePolicyOptions
        {
            MinimumSameSitePolicy = SameSiteMode.Strict,
        };
        app.UseCookiePolicy(cookiePolicyOptions);

        app.UseRequestLocalization(new RequestLocalizationOptions
        {
            DefaultRequestCulture = new RequestCulture("en-US"),
            SupportedCultures = this.SupportedCultures,
            SupportedUICultures = this.SupportedCultures
        });

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

2 个答案:

答案 0 :(得分:1)

按照https://leastprivilege.com/2018/06/14/mixing-ui-and-api-endpoints-in-asp-net-core-2-1-aka-dynamic-scheme-selection/

所述使用ForwardDefaultSelector

       services
            .AddAuthentication(sharedOptions =>
            {
                sharedOptions.DefaultScheme = "dynamic";
            })
            .AddPolicyScheme("dynamic", "Cookie or JWT", options =>
            {
                options.ForwardDefaultSelector = context =>
                {
                    var authHeader = context.Request.Headers["Authorization"].FirstOrDefault();
                    var isApiPath = context.Request.Path.StartsWithSegments("/api");
                    if (authHeader?.StartsWith("Bearer ") || isApiPath)
                    {
                        return JwtBearerDefaults.AuthenticationScheme;
                    }
                    return CookieAuthenticationDefaults.AuthenticationScheme;
                };
            })
            .AddJwtBearer(o =>
            {
                o.Authority = Configuration["JWT:Authentication:Authority"];
                o.Audience = Configuration["JWT:Authentication:ClientId"];
                o.SaveToken = true;
            })
            .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme);

            ...

            }

答案 1 :(得分:0)

我通过保留上面的Startup.cs来解决了这个问题,但是随后更改了我对控制器的授权方式。授权后,我会设定一个特定的方案。 Cookie方案可以使我登录cookie,OpenIdConnect方案可以使我登录OpenIdConnect。在构建应用程序时,我可能需要花些时间来处理资源,但这似乎可以解决问题。幸运的是,通过cookie登录的用户与通过OpenIDConnect登录的用户之间存在业务逻辑差异。

[Authorize(AuthenticationSchemes = OpenIdConnectDefaults.AuthenticationScheme)]