【问题标题】:CORS Policy Not Working in IdentityServer4CORS 策略在 IdentityServer4 中不起作用
【发布时间】:2021-07-04 04:25:57
【问题描述】:

我正在使用 IdentityServer4 (IS4) 连接到 AzureAD 进行身份验证。我在 AzureAD 上创建了应用程序,并使用了正确的 ClientID 和 Tenant ID。

我在登录时收到以下错误:

[15:13:04 Information] Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler
AuthenticationScheme: OpenIdConnect was challenged.

[15:13:06 Debug] IdentityServer4.Hosting.CorsPolicyProvider
CORS request made for path: /signin-oidc from origin: https://login.microsoftonline.com but was ignored because path was not for an allowed IdentityServer CORS endpoint

[15:13:06 Information] Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler
AuthenticationScheme: Identity.External signed in.

请,我请求指导我,因为这里出了什么问题。

这是我的整个 Startup.cs 的样子:

// Copyright (c) Brock Allen & Dominick Baier. All rights reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.


using IdentityServer4;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Microsoft.EntityFrameworkCore;
using IdentityServerHost.Quickstart.UI;
using System.Reflection;
using IdentityServer.Models;
using Microsoft.AspNetCore.Identity;
using IdentityServer.Data;
using IdentityServer4.Configuration;
using System;
using Microsoft.AspNetCore.Authentication;
using IdentityServer4.Services;
using Microsoft.Extensions.Logging;
using System.Collections.Generic;

namespace IdentityServer
{
    public class Startup
    {
        public IWebHostEnvironment Environment { get; }
        public IConfiguration Configuration { get; }

        public Startup(IWebHostEnvironment environment, IConfiguration configuration)
        {
            Environment = environment;
            Configuration = configuration;
        }

        public void ConfigureServices(IServiceCollection services)
        {

            var connectionString = Configuration.GetConnectionString("DefaultConnection");
            var migrationsAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name;

            services.AddControllersWithViews();
            services.AddDbContext<IdentityServerContext>(options =>
    options.UseMySql(connectionString, sql => sql.MigrationsAssembly(migrationsAssembly))
);

            services.AddDbContext<Data.ConfigurationDbContext>(options => options.UseMySql(connectionString, sql => sql.MigrationsAssembly(migrationsAssembly)));

            services.AddIdentity<ApplicationUser, IdentityRole>(options =>
            {
                options.SignIn.RequireConfirmedEmail = false;
                //New added
                options.Password.RequiredLength = 4;
                options.Password.RequireLowercase = false;
                options.Password.RequireUppercase = false;
                options.Password.RequireDigit = false;
                options.Password.RequireNonAlphanumeric = false;

                options.Lockout.AllowedForNewUsers = true;
                options.Lockout.DefaultLockoutTimeSpan = new TimeSpan(0, 15, 00);
                options.Lockout.MaxFailedAccessAttempts = 5;
            })
            .AddEntityFrameworkStores<IdentityServerContext>()
            .AddDefaultTokenProviders();

            var builder = services.AddIdentityServer(options =>
                {
                    options.Events.RaiseErrorEvents = true;
                    options.Events.RaiseInformationEvents = true;
                    options.Events.RaiseFailureEvents = true;
                    options.Events.RaiseSuccessEvents = true;

                    // see https://identityserver4.readthedocs.io/en/latest/topics/resources.html
                    options.EmitStaticAudienceClaim = true;
                    options.UserInteraction.LoginUrl = "/Account/Login";
                    options.UserInteraction.LogoutUrl = "/Account/Logout";
                    options.Authentication = new IdentityServer4.Configuration.AuthenticationOptions()
                    {
                        CookieLifetime = TimeSpan.FromHours(10), // ID server cookie timeout set to 10 hours
                        CookieSlidingExpiration = true
                    };
                })
                //.AddTestUsers(TestUsers.Users)
                // this adds the config data from DB (clients, resources, CORS)
                .AddConfigurationStore(options =>
                {
                    options.ConfigureDbContext = builder => builder.UseMySql(connectionString, sql => sql.MigrationsAssembly(migrationsAssembly));

                })
                // this adds the operational data from DB (codes, tokens, consents)
                .AddOperationalStore(options =>
                {
                    options.ConfigureDbContext = builder => builder.UseMySql(connectionString, sql => sql.MigrationsAssembly(migrationsAssembly));

                    // this enables automatic token cleanup. this is optional.
                    options.EnableTokenCleanup = true;
                })
                .AddAspNetIdentity<ApplicationUser>()
                .AddProfileService<IdentityProfileService>();

            services.AddCors(options =>
            {
                options.AddPolicy("CorsPolicy",
                    builder => builder.AllowAnyOrigin()
                    .AllowAnyMethod()
                    .AllowAnyHeader());
            });

            var autBuilder = services.AddAuthentication();

            //Azure AD
            autBuilder.AddAzureAd(options => Configuration.Bind("AzureAd", options));

            // not recommended for production - you need to store your key material somewhere secure
            builder.AddDeveloperSigningCredential();

            /*
            services.AddAuthentication()
                .AddGoogle(options =>
                {
                    options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;

                    // register your IdentityServer with Google at https://console.developers.google.com
                    // enable the Google+ API
                    // set the redirect URI to https://localhost:5001/signin-google
                    options.ClientId = "copy client ID from Google here";
                    options.ClientSecret = "copy client secret from Google here";
                });
            */
        }

        public void Configure(IApplicationBuilder app)
        {
            if (Environment.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
                app.UseDatabaseErrorPage();
            }

            app.UseStaticFiles();

            app.UseRouting();

            app.UseCors("CorsPolicy");

            app.UseIdentityServer();
            app.UseAuthorization();


            app.UseEndpoints(endpoints =>
            {
                endpoints.MapDefaultControllerRoute();
            });


        }
    }
}

还有 Azure Extension.cs

using System;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;

namespace Microsoft.AspNetCore.Authentication
{
    public static class AzureAdAuthenticationBuilderExtensions
    {        
        public static AuthenticationBuilder AddAzureAd(this AuthenticationBuilder builder)
            => builder.AddAzureAd(_ => { });

        public static AuthenticationBuilder AddAzureAd(this AuthenticationBuilder builder, Action<AzureAdOptions> configureOptions)
        {
            builder.Services.Configure(configureOptions);
            builder.Services.AddSingleton<IConfigureOptions<OpenIdConnectOptions>, ConfigureAzureOptions>();
            builder.AddOpenIdConnect();
            return builder;
        }

        private class ConfigureAzureOptions: IConfigureNamedOptions<OpenIdConnectOptions>
        {
            private readonly AzureAdOptions _azureOptions;

            public ConfigureAzureOptions(IOptions<AzureAdOptions> azureOptions)
            {
                _azureOptions = azureOptions.Value;
            }

            public void Configure(string name, OpenIdConnectOptions options)
            {
                options.ClientId = _azureOptions.ClientId;
                options.Authority = $"{_azureOptions.Instance}{_azureOptions.TenantId}";
                options.UseTokenLifetime = true;
                options.CallbackPath = _azureOptions.CallbackPath;
                options.RequireHttpsMetadata = false;
            }

            public void Configure(OpenIdConnectOptions options)
            {
                Configure(Options.DefaultName, options);
            }
        }
    }
}

还有 appsettings.json

Appsettings.json
{
  "ConnectionStrings": {
    //"DefaultConnection": "connectiong_string"
  },
  "AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "Domain": "",
    "TenantId": "xxxxxxxxxxxxxxxxxxxxxxxxxx",
    "ClientId": "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy",
    "CallbackPath": "/signin-oidc"
  },
  "TimeSettings": {
    "AbsoluteRefreshTokenLifetime": 15552000,
    "SlidingRefreshTokenLifetime": 1296000,
    "IdentityTokenLifetime": 300,
    "AccessTokenLifetime": 300,
    "AuthorizationCodeLifetime": 300

  }
}

【问题讨论】:

    标签: azure-active-directory identityserver4 openid-connect


    【解决方案1】:

    IdentityServer 对其客户端发出的请求有自己的 CORS 设置。

    您使用客户端配置上的 AllowedCorsOrigins 集合来进行设置。只需将客户端的来源添加到集合中,IdentityServer 中的默认配置将参考这些值以允许来自来源的跨域调用。

    new Client
    {
        ...
        AllowedCorsOrigins = new List<string>
        {
             "http://www.myclient.com"
         }
    }
    

    很难说,一个想法是是否应该将 "CallbackPath": "/signin-oidc" 的使用更改为其他 URL,以免与使用 /signin-oidc 的其他内容冲突。

    例如在他们使用的代码here中:

    .AddOpenIdConnect("aad", "使用 Azure AD 登录", options => { ...

    options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
    options.SignOutScheme = IdentityServerConstants.SignoutScheme;
    
    options.ResponseType = "id_token";
    options.CallbackPath = "/signin-aad";
    options.SignedOutCallbackPath = "/signout-callback-aad";
    options.RemoteSignOutPath = "/signout-aad";
    

    【讨论】:

    • 你好托雷。非常感谢您的回复。实际上,我已将客户端和 cors 添加到数据库中。请找到截图。客户表 - snipboard.io/LMfYDR.jpg ClientCorgsOrigin 表 - snipboard.io/UGdFSj.jpg 我无法理解我哪里出错了:(
    • 您在浏览器控制台中是否收到任何 CORS 错误?您确定客户端不是 localhost 5003 上的第一个客户端吗? (客户端 ID 4)?
    • 您可以从我们的 Startup.cs 文件中发布更多信息吗? (ConfigureServices 方法)如何在该方法中添加 AzureAD?我认为问题在于返回 URL /signin-oidc 可能是错误的。
    • 是的。控制台中关于 favicon - screenshot - snipboard.io/ltLwFq.jpg 和 ISR 的属性 - snipboard.io/sPur5q.jpg 的错误
    • 是的。代码链接 - vsit.click/we9sb 非常感谢您为此付出了如此多的时间和精力。
    猜你喜欢
    • 2015-11-14
    • 2019-07-09
    • 2022-10-23
    • 2013-03-30
    • 2023-04-07
    • 2021-12-05
    • 2019-06-13
    • 2020-05-28
    • 1970-01-01
    相关资源
    最近更新 更多