仅在 Angular 7 网络应用程序中为 "https://localhost:44361/connect/token" 获取错误 "blocked by CORS policy"

Getting an error "blocked by CORS policy" only for "https://localhost:44361/connect/token" in Angular 7 web app

完整错误如下图

Access to XMLHttpRequest at 'https://localhost:44361/connect/token' from origin 'http://localhost:4200' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

我在 .net core web api 的启动 class 中启用了核心策略,如下所示。

My ConfigureService method

        public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
        services.AddDbContext<LEAFDDbContext>(options =>
        options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"), builder =>
        {
            builder.EnableRetryOnFailure(5, TimeSpan.FromSeconds(10), null);
        }));

        services.AddIdentity<ApplicationUser, ApplicationRole>()
                .AddEntityFrameworkStores<LEAFDDbContext>()
                .AddDefaultTokenProviders();

        services.AddCors(options =>
        {
        options.AddPolicy("CorsPolicy",
            builder => builder.AllowAnyOrigin()
                .AllowAnyMethod()
                .AllowAnyHeader()
                .AllowCredentials());
        });
        Installer.ConfigureServices(services);
        //services.AddCors();
        //services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
        //services.AddSingleton<IAuthenticationSchemeProvider, CustomAuthenticationSchemeProvider>();


        //services.AddAuthentication(options =>
        //{
        //    //options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        //    //options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        //    //options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        //    options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
        //    options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
        //})
        services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
        .AddCookie(options =>
        {
            options.Events.OnRedirectToLogin = ctx =>
            {
                // if it is an ajax/api request, don't redirect
                // to login page.
                if (!(IsAjaxRequest(ctx.Request) || IsApiRequest(ctx.Request)))
                {
                    ctx.Response.Redirect(ctx.RedirectUri);
                    return Task.CompletedTask;
                }
                ctx.Response.StatusCode = StatusCodes.Status401Unauthorized;
                return ctx.Response.WriteAsync("Unauthorized");
            };
        })
        .AddOAuthValidation()
        //services.AddAuthentication()
        .AddOpenIdConnectServer(options =>
        {
            options.Provider = new AuthorizationProvider();

            // Enable the authorization and token endpoints.
            options.AuthorizationEndpointPath = "/connect/authorize";
            options.TokenEndpointPath = "/connect/token";
            options.AllowInsecureHttp = true;

            // Note: to override the default access token format and use JWT, assign AccessTokenHandler:
            //
            options.AccessTokenHandler = new JwtSecurityTokenHandler
            {
                InboundClaimTypeMap = new Dictionary<string, string>(),
                OutboundClaimTypeMap = new Dictionary<string, string>()
            };

            //
            // Note: when using JWT as the access token format, you have to register a signing key.
            //
            // You can register a new ephemeral key, that is discarded when the application shuts down.
            // Tokens signed using this key are automatically invalidated and thus this method
            // should only be used during development:
            //
            options.SigningCredentials.AddEphemeralKey();
            //
            // On production, using a X.509 certificate stored in the machine store is recommended.
            // You can generate a self-signed certificate using Pluralsight's self-cert utility:
            // https://s3.amazonaws.com/pluralsight-free/keith-brown/samples/SelfCert.zip
            //
            //options.SigningCredentials.AddCertificate("7D2A741FE34CC2C7369237A5F2078988E17A6A75");

        });

    }

Configure method

        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseHsts();
        }
        //app.UseOAuthValidation();
        app.UseAuthentication();
        app.UseMvc();

        app.UseMiddleware();

        app.UseCors("CorsPolicy");
        //app.UseCors(builder => builder.AllowAnyHeader().AllowAnyMethod().AllowAnyOrigin().AllowCredentials());
        app.UseWelcomePage();


    }

除了“https://localhost:44361/connect/token”之外的所有其他调用都按预期工作:获取令牌时。

我正在将来自 Angular 7 网络应用程序的所有请求发送到 .net 核心网络 api。

作为解决方法,我安装了来自 google chrome 的跨源资源共享扩展,我需要更改代码级别以永久解决此问题。

这是我想出的最终解决方案。

我没有直接从 Angular 7 应用程序调用“https://localhost:44361/connect/token”,而是在 API 控制器中创建了一个方法,该方法将调用上述调用并获取令牌。因此,每当我需要时,我只需要在 API 控制器中调用新创建的方法。

新api调用如下

        [HttpPost]
    [Route("/api/[controller]/Token")]
    [EnableCors("CorsPolicy")]
    public async Task<ContentResult> Token(LoginTokenRequestModel model)
    {
        string UserId = string.Empty;
        try
        {
            using (HttpClient httpClient = new HttpClient())
            {
                if (!String.IsNullOrEmpty(model.Email))
                {

                    var content = new FormUrlEncodedContent(new KeyValuePair<string, string>[]{
                         new KeyValuePair<string, string>("grant_type", model.grant_type),
                         new KeyValuePair<string, string>("client_secret", model.client_secret),
                         new KeyValuePair<string, string>("client_id", model.client_id),
                         new KeyValuePair<string, string>("username", model.Email),
                         new KeyValuePair<string, string>("password", model.Password),
                    });
                    string apiURL = "https://localhost:44361";

                    var response = await httpClient.PostAsync(apiURL + "/connect/token", content);
                    var resultContent = await response.Content.ReadAsStringAsync();

                    if (response.IsSuccessStatusCode)
                    {
                        var token = JsonConvert.DeserializeObject<object>(resultContent);
                        return new ContentResult
                        {
                            Content = token.ToString(),
                            ContentType = "text/plain",
                            StatusCode = 200
                        };
                    }

                    return new ContentResult
                    {
                        Content = JsonConvert.DeserializeObject<object>(resultContent).ToString(),
                        ContentType = "text/plain",
                        StatusCode = 200
                    };
                }
            }
        }

        catch (Exception ex)
        {
            return new ContentResult
            {
                Content = ex.Message,
                ContentType = "text/plain",
                StatusCode = 400
            };
        }
        return new ContentResult
        {
            Content = "",
            ContentType = "text/plain",
            StatusCode = 400
        };

    }

这解决了我的问题。

app.useMvc()之前使用app.UseCors() 。当涉及到中间件调用时,顺序很重要。就个人而言,我将其保存在确定 if-else.

的环境中
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
            app.UseCors("CorsDevPolicy");
        }
        else
        {
            // 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.UseMiddleware(typeof(ErrorHandlingMiddleware));
        app.UseMvc();
    }