使用 Angular 的 CORS 问题:8.2.14 和 .NET CORE 3.1 REST API 授权
Posted
技术标签:
【中文标题】使用 Angular 的 CORS 问题:8.2.14 和 .NET CORE 3.1 REST API 授权【英文标题】:CORS Problem using Angular: 8.2.14 and .NET CORE 3.1 REST API Authorization 【发布时间】:2020-09-10 13:12:59 【问题描述】:我一直在开发一个简单的 Angular 项目,该项目连接到使用 .NET CORE 3.1 开发的 REST API
我遇到的问题是使用 Chrome 登录时出错。我尝试了许多不同的选项,并查看了许多 *** 问题和答案,但都没有奏效。我试图添加所有相关的代码和文件。如果还有其他需要,请告诉我。
这是我的 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>();
【问题讨论】:
【参考方案1】:只需将您对 web.config 所做的所有更改恢复原状,并将以下代码添加到 Startup.cs 中的 Configure 方法:
app.UseCors(builder =>
builder
.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader();
);
【讨论】:
web api 需要通过代码设置 cors,而不是 web.config 我忘了添加我的 Startup.cs 文件。现在在上面。我已将以上是关于使用 Angular 的 CORS 问题:8.2.14 和 .NET CORE 3.1 REST API 授权的主要内容,如果未能解决你的问题,请参考以下文章
无法使用 Spring Boot 和 Angular 修复 CORS 问题 [重复]
使用 Angular 的 Stripe API 的 CORS 问题
使用 Angular 向 facebook oauth 发出 CORS 问题
使用 Django 和 Angular 的 CORS 预检请求