【发布时间】:2020-09-10 13:12:59
【问题描述】:
我一直在开发一个简单的 Angular 项目,该项目连接到使用 .NET CORE 3.1 开发的 REST API
我遇到的问题是使用 Chrome 登录时出错。我尝试了许多不同的选项,并查看了许多 stackoverflow 问题和答案,但都没有奏效。我试图添加所有相关的代码和文件。如果还有其他需要,请告诉我。
<?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>();
}
}
}
【问题讨论】: