【问题标题】:CORS Problem using Angular: 8.2.14 and .NET CORE 3.1 REST API Authorization使用 Angular 的 CORS 问题:8.2.14 和 .NET CORE 3.1 REST API 授权
【发布时间】:2020-09-10 13:12:59
【问题描述】:

我一直在开发一个简单的 Angular 项目,该项目连接到使用 .NET CORE 3.1 开发的 REST API

我遇到的问题是使用 Chrome 登录时出错。我尝试了许多不同的选项,并查看了许多 stackoverflow 问题和答案,但都没有奏效。我试图添加所有相关的代码和文件。如果还有其他需要,请告诉我。

这是我的 web.config

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <location path="." inheritInChildApplications="false">
    <system.webServer>
  <httpProtocol>
      <customHeaders>
      <add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, OPTIONS" />
      <add name="Access-Control-Allow-Origin" value="*" />
      <add name="Access-Control-Allow-Headers" value="Content-Type" />
    </customHeaders>
  </httpProtocol>
      <handlers>
        <add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified" />
      </handlers>
      <aspNetCore processPath="%LAUNCHER_PATH%" stdoutLogEnabled="true" stdoutLogFile=".\logs\stdout" arguments="%LAUNCHER_ARGS%" hostingModel="InProcess">
        <environmentVariables>
          <environmentVariable name="FORTRESS_ENVIRONMENT" value="Development" />
          <environmentVariable name="FORTRESS_APPNAME" value="TEST APP" />
          <environmentVariable name="ASPNETCORE_HTTPS_PORT" value="3100" />
          <environmentVariable name="COMPLUS_ForceENC" value="1" />
        </environmentVariables>
      </aspNetCore>
      <security>
        <requestFiltering removeServerHeader="true" />
      </security>
    </system.webServer>
  </location>
</configuration>

这是我的 app.json 文件代码

    {
      "AppName": "Contacts Service",
      "AllowedHosts": "*",
      "ConnectionString": "Server=FORTDSVM01;Initial Catalog=BankSCL;Integrated Security=true",
      "Kestrel": {
        "EndpointDefaults": {
          "Protocols": "Http1"
        }
      },
      "Serilog": {
        "MinimumLevel": {
          "Override": {
            "System": "Warning",
            "Microsoft": "Warning",
            "Microsoft.Hosting.Lifetime": "Information"

          }
        },
        "WriteTo:Async": {
          "Name": "Async",
          "Args": {
            "configure": [
              {
                "Name": "File",
                "Args": {
                  "isJson": true,
                  "formatter": "Serilog.Formatting.Compact.CompactJsonFormatter, Serilog.Formatting.Compact",
                  "path": "c:\\apps\\contacts-svc\\logs\\.log",
                  "rollingInterval": "Day",
                  "rollOnFileSizeLimit": true,
                  "fileSizeLimitBytes": "5000000",
                  "retainedFileCountLimit": null,
                  "shared": true
                }
              }
            ]
          }
        },
        "AppSettings": {
          "Secret": "THIS IS USED TO SIGN AND VERIFY JWT TOKENS, REPLACE IT WITH YOUR OWN SECRET, IT CAN BE ANY STRING"
        }
      },
      "Config": {
        "JWTKey": "12345678!@#$%^&*",
        "ValidIssuer": "https://localhost:3100/",
        "ValidAudience": "https://localhost:3100/",
        "SenderMailAddress": "test@gmail.com",
        "SenderMailPassword": "!123ABC!",
        "MailServerName": "smtp.gmail.com",
        "MailPortNumber": "465"
      }
    }

This is my Startup.cs

    using System;
    using System.Net.Http;
    using System.Security.Claims;
    using System.Text;
    using AutoMapper;
    using Fortress.Framework;
    using Fortress.Framework.DependencyInjection;
    using Fortress.Service.Api.Helpers;
    using Fortress.Service.Api.Mapper;
    using Fortress.Service.Api.Repository.Repository;
    using Fortress.Service.Api.Services;
    using Microsoft.AspNetCore.Authentication.JwtBearer;
    using Microsoft.AspNetCore.Builder;
    using Microsoft.AspNetCore.Hosting;
    using Microsoft.Extensions.Configuration;
    using Microsoft.Extensions.DependencyInjection;
    using Microsoft.IdentityModel.Tokens;

    namespace Fortress.Service.Api
    {
        public class Startup : ApiBaseStartup<Startup>
        {
            static int Main(string[] args) => Run(args);
           // readonly string MyAllowSpecificOrigins = "_myAllowSpecificOrigins";

            protected override void ConfigureApp(IApplicationBuilder app, IWebHostEnvironment env)
            {

               // app.UseHttpsRedirection();

                app.UseRouting();

                app.UseCors("AllowAllHeaders");

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

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

            protected override void ConfigureAppServices(IServiceCollection services)
            {
                services.AddCors(options => options.AddPolicy("AllowAllHeaders", build =>
                {
                    build.WithOrigins("http://localhost:4200")
                         .AllowAnyMethod()
                         .AllowAnyHeader();
                }));

                services.AddAutoMapper(typeof(MapperProfile));
                services.AddSqlServer<ContactsContext>(Configuration);
                services.AddSqlServer<PoliciesContext>(Configuration);

                services.AddControllers();

                // configure strongly typed settings objects
                var appSettingsSection = Configuration.GetSection("AppSettings");
                services.Configure<AppSettings>(appSettingsSection);

                //// configure jwt authentication
                var appSettings = appSettingsSection.Get<AppSettings>();
                var key = Encoding.ASCII.GetBytes(Configuration.GetValue<string>("Config:JWTKey"));

                services.AddAuthentication(x =>
                {
                    x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                    x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
                })
                .AddJwtBearer(x =>
                {
                    x.RequireHttpsMetadata = false;
                    x.SaveToken = true;
                    x.TokenValidationParameters = new TokenValidationParameters
                    {
                        ValidateIssuerSigningKey = true,
                        //Same Secret key will be used while creating the token
                        IssuerSigningKey = new SymmetricSecurityKey(key),
                        ValidateIssuer = true,
                        //Usually, this is your application base URL
                        ValidIssuer = Configuration.GetValue<string>("Config:ValidIssuer"),
                    ValidateAudience = true,
                        //Here, we are creating and using JWT within the same application.
                        //In this case, base URL is fine.
                        //If the JWT is created using a web service, then this would be the consumer URL.
                        ValidAudience = Configuration.GetValue<string>("Config:ValidAudience"),
                    RequireExpirationTime = true,
                        ValidateLifetime = true,
                        ClockSkew = TimeSpan.Zero
                    };
                });

                // configure DI for application services
                services.AddScoped<IUserService, UserService>();


            }
        }
    }

This is my launchSettings.json

{
  "iisSettings": {
    "windowsAuthentication": false,
    "anonymousAuthentication": true,
    "iisExpress": {
      "applicationUrl": "http://localhost:3100", //64929
      "sslPort": 3100
    }
  },
  "$schema": "http://json.schemastore.org/launchsettings.json",
  "profiles": {
    "IIS Express": {
      "commandName": "IISExpress",
      "launchUrl": "api/ping",
      "environmentVariables": {
        "FORTRESS_ENVIRONMENT": "Development"
      }
    },
    "Fortress.Service.Api": {
      "commandName": "Project",
      "launchUrl": "weatherforecast",
      "environmentVariables": {
        "FORTRESS_ENVIRONMENT": "Development"
      },
      "applicationUrl": "https://localhost:3100;http://localhost:3000"
    },
    "Docker": {
      "commandName": "Docker",
      "launchBrowser": true,
      "launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/api/ping",
      "environmentVariables": {
        "FORTRESS_URLS": "https://+:3100;http://+:80",
        "FORTRESS_HTTPS_PORT": "3100"
      },
      "httpPort": 3000,
      "useSSL": true,
      "sslPort": 3100
    }
  }
}

这是我的用户控制器

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Fortress.Framework;
using Fortress.Service.Api.Business.Contacts;
using Fortress.Service.Api.Models;
using Fortress.Service.Api.Services;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Cors;
//using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
//using System.Web.Http.Cors;

namespace Fortress.Service.Api.Controllers
{
    //[Authorize(AuthenticationSchemes = "Bearer")]
    [AllowAnonymous]
    [FortressApi("Users")]
      public class UsersController : FortressController
    {
        private IUserService _userService;

        public UsersController(IUserService userService)
        {
            _userService = userService;
        }

        // [AllowAnonymous]
        //[EnableCors("AllowAllHeaders")]
        [HttpPost("ValidateCredentials")]
        [Route("Login")]
        public async Task<UserCredentialOutput> ValidateCredentials(
            [FromServices] IGetCredentialService service,
            [FromBody] UserCredentialInput userCredentialInput, CancellationToken token)
        {

            var response = await ExecuteServiceAsync(service, userCredentialInput, token);
            response.Password = userCredentialInput.Password;

            var user = _userService.Authenticate(response);
            return new UserCredentialOutput
            {
                ContactID = user.ContactID,
                FirstName = user.FirstName,
                LastName = user.LastName,
                UserName = user.UserName,
                Roles = user.Roles,
                EmailID = user.EmailID,
                Token = user.Token
            };
        }
    }
}

这是我调用 API 的 Angular 服务函数

validateCredentials(formData: FormData): Observable<UserCredentialOutput> {


        return this.api.post<UserCredentialOutput>('Users/Login', formData);


    }

我完全忘了添加我的 Startup.cs 文件——在这里

using System;
using System.Net.Http;
using System.Security.Claims;
using System.Text;
using AutoMapper;
using Fortress.Framework;
using Fortress.Framework.DependencyInjection;
using Fortress.Service.Api.Helpers;
using Fortress.Service.Api.Mapper;
using Fortress.Service.Api.Repository.Repository;
using Fortress.Service.Api.Services;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Tokens;
using Microsoft.AspNetCore.Mvc.Cors;

namespace Fortress.Service.Api
{
    public class Startup : ApiBaseStartup<Startup>
    {
        static int Main(string[] args) => Run(args);
       // readonly string MyAllowSpecificOrigins = "_myAllowSpecificOrigins";

        protected override void ConfigureApp(IApplicationBuilder app, IWebHostEnvironment env)
        {


            //app.UseOptions();
            app.UseHttpsRedirection();
            app.UseRouting();

            app.UseCors("AllowAllHeaders");
            //app.UseMvc();
            app.UseAuthorization();
            app.UseAuthentication();

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

        protected override void ConfigureAppServices(IServiceCollection services)
        {
            services.AddCors(options => options.AddPolicy("AllowAllHeaders", build =>
            {
                build.WithOrigins("http://localhost:4200")
                     .AllowAnyMethod()
                     .AllowAnyHeader();
            }));

            services.AddMvc();

            //services.Configure<MvcOptions>(options =>
            //{
            //    options.Filters.Add(new CorsAuthorizationFilterFactory("AllowMyOrigin"));
            //});

            services.AddAutoMapper(typeof(MapperProfile));
            services.AddSqlServer<ContactsContext>(Configuration);
            services.AddSqlServer<PoliciesContext>(Configuration);

            services.AddControllers();

            // configure strongly typed settings objects
            var appSettingsSection = Configuration.GetSection("AppSettings");
            services.Configure<AppSettings>(appSettingsSection);

            //// configure jwt authentication
            var appSettings = appSettingsSection.Get<AppSettings>();
            var key = Encoding.ASCII.GetBytes(Configuration.GetValue<string>("Config:JWTKey"));

            services.AddAuthentication(x =>
            {
                x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            })
            .AddJwtBearer(x =>
            {
                x.RequireHttpsMetadata = false;
                x.SaveToken = true;
                x.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidateIssuerSigningKey = true,
                    //Same Secret key will be used while creating the token
                    IssuerSigningKey = new SymmetricSecurityKey(key),
                    ValidateIssuer = true,
                    //Usually, this is your application base URL
                    ValidIssuer = Configuration.GetValue<string>("Config:ValidIssuer"),
                ValidateAudience = true,
                    //Here, we are creating and using JWT within the same application.
                    //In this case, base URL is fine.
                    //If the JWT is created using a web service, then this would be the consumer URL.
                    ValidAudience = Configuration.GetValue<string>("Config:ValidAudience"),
                RequireExpirationTime = true,
                    ValidateLifetime = true,
                    ClockSkew = TimeSpan.Zero
                };
            });

            // configure DI for application services
            services.AddScoped<IUserService, UserService>();


        }
    }
}

【问题讨论】:

    标签: c# angular .net-core cors


    【解决方案1】:

    只需将您对 web.config 所做的所有更改恢复原状,并将以下代码添加到 Startup.cs 中的 Configure 方法:

    app.UseCors(builder =>
            {
                builder
                    .AllowAnyOrigin()
                    .AllowAnyMethod()
                    .AllowAnyHeader();
            });
    

    【讨论】:

    • web api 需要通过代码设置 cors,而不是 web.config
    • 我忘了添加我的 Startup.cs 文件。现在在上面。我已将 和 customHeaders> 从 web.config 文件中取出。同样的问题。它在邮递员中工作得很好。就在我从我的角度项目中推送时,它每次都会出错。
    • 它与邮递员一起工作,因为邮递员没有设置源头,但浏览器确实在请求中设置了这个头。这不是角度的问题。你只需要在你的 .net 核心代码中修复它,它就可以正常工作了。
    • 从 startup.cs 中的 ConfigureAppServices 方法中删除 services.AddCors... 块,并将同一文件中 ConfigureApp 方法中的 app.UseCors 方法更改为此答案中提供的格式
    • 好的,我已经从 ConfigureAppServices // services.AddCors(); 中删除了以下内容并将以下内容添加到 ConfigureApp app.UseCors(builder => { builder .AllowAnyOrigin() .AllowAnyMethod() .AllowAnyHeader(); });没有喜悦。 :(
    猜你喜欢
    • 2020-07-30
    • 2020-04-06
    • 2021-02-14
    • 2020-03-04
    • 2021-12-06
    • 1970-01-01
    • 2019-03-18
    • 2020-08-02
    • 2021-09-19
    相关资源
    最近更新 更多