INFO - I'm running and debugging my (Angular 10 / ASP.Net 5) site successfully in VS Code connecting to localhost:4200 with >ng serve and >dotnet run, I now want to publish it to Azure, but first I want to test it locally on Kestrel only, by building the Angular project to the wwwroot folder in the.Net API project and running the site from localhost:5001. I build (>ng build) to wwwroot in my API project folder, I see all the Angular files being created in the wwwroot folder, and then I execute >dotnet run.
I see
Now listening on: https://localhost:5001
and then I open the browser to hit that url and I see these errors in the terminal
info: Microsoft.AspNetCore.Hosting.Diagnostics[1] Request starting HTTP/1.1 GET https://localhost:5001/ - - info: Microsoft.AspNetCore.Authorization.DefaultAuthorizationService[2] Authorization failed. These requirements were not met: DenyAnonymousAuthorizationRequirement: Requires an authenticated user. info: Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler[12] AuthenticationScheme: Bearer was challenged. info: Microsoft.AspNetCore.Authorization.DefaultAuthorizationService[2] Authorization failed. These requirements were not met: DenyAnonymousAuthorizationRequirement: Requires an authenticated user. info: Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler[12] AuthenticationScheme: Bearer was challenged. info: Microsoft.AspNetCore.Hosting.Diagnostics[2] Request finished HTTP/1.1 GET https://localhost:5001/ - - - 401 0 - 70.3847ms
QUESTION - Is this a configuration issue? A CORS/permission issue? A authentication issue? A folder/path issue?
Here is additional code to help anyone that might be able to help me understand what is going on
Startup.cs
ConfigureServices()
public void ConfigureServices(IServiceCollection services)
{
services.AddAutoMapper(typeof(MappingEvents));
services.AddAutoMapper(typeof(MappingMembers));
services.AddAutoMapper(typeof(MappingUsers));
services.AddAutoMapper(typeof(MappingYogabands));
services.AddAutoMapper(typeof(MappingReviews));
// services.AddControllers();
services.AddControllers()
.AddNewtonsoftJson(opt =>
{
opt.SerializerSettings.ReferenceLoopHandling =
Newtonsoft.Json.ReferenceLoopHandling.Ignore;
});
services.AddDbContext<DataContext>(x =>
x.UseSqlServer(_config.GetConnectionString("SqlServerConnection"), y => y.UseNetTopologySuite()));
services.AddTransient<IEmailSender, EmailSender>();
services.Configure<AuthMessageSenderOptions>(_config.GetSection("SendGrid"));
services.Configure<ConfirmationOptions>(_config.GetSection("Confirmation"));
services.Configure<CloudinarySettings>(_config.GetSection("CloudinarySettings"));
services.AddApplicationServices();
services.AddIdentityServices(_config);
services.AddSwaggerDocumentation();
// telling out client app, that if it's running on an unsecure port, we won't return a header,
// that will allow our browser to display that information
// * only allowed to access info from localhost:4200, all others will be denied?
services.AddCors(opt =>
{
opt.AddPolicy("CorsPolicy", policy =>
{
policy.AllowAnyHeader().AllowAnyMethod().WithOrigins("https://localhost:4200");
});
});
}
Configure()
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseMiddleware<ExceptionMiddleware>();
// when coming into the server and we don't have an endpoint that matches the request, then we hit this below
// it will then re direct to our error controller, pass in the status code and return an object result
app.UseStatusCodePagesWithReExecute("/errors/{0}"); // after creating ErrorController
app.UseHttpsRedirection();
app.UseRouting();
app.UseCors("CorsPolicy");
app.UseAuthentication();
app.UseAuthorization();
app.UseSwaggerDocumention();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers().RequireAuthorization();
// endpoints.MapControllers();
endpoints.MapFallbackToController("Index", "Fallback");
});
}
AddIdentityService() (called in ConfigureServices())
public static IServiceCollection AddIdentityServices(this IServiceCollection services, IConfiguration config)
{
services.Configure<IdentityOptions>(options =>
{
options.User.RequireUniqueEmail = true;
options.User.AllowedUserNameCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._@";
});
var builder = services.AddIdentityCore<User>(opt =>
{
opt.Password.RequireDigit = false;
opt.Password.RequiredLength = 2;
opt.Password.RequireNonAlphanumeric = false;
opt.Password.RequireUppercase = false;
// *******************************************************
// for email confirmation
opt.SignIn.RequireConfirmedEmail = true;
// *******************************************************
});
builder = new IdentityBuilder(builder.UserType, typeof(Role), builder.Services);
// AddDefaultTokenProviders() allows the ability to create a token to send to user when they forgot password
builder.AddEntityFrameworkStores<DataContext>().AddDefaultTokenProviders();
// for roles
builder.AddRoleValidator<RoleValidator<Role>>();
builder.AddRoleManager<RoleManager<Role>>();
builder.AddSignInManager<SignInManager<User>>();
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(config["Token:Key"])),
ValidIssuer = config["Token:Issuer"],
ValidateIssuer = true,
ValidateAudience = false
};
});
services.AddAuthorization(options =>
{
options.AddPolicy("RequireAdminRole", policy => policy.RequireRole("Admin"));
options.AddPolicy("ModeratePhotoRole", policy => policy.RequireRole("Admin", "Moderator"));
options.AddPolicy("VipOnly", policy => policy.RequireRole("VIP"));
});
return services;
}
build section of Angular.json file
"build": {
"builder": "@angular-devkit/build-angular:browser",
"options": {
"allowedCommonJsDependencies": ["angular2-wizard", "hammerjs"],
"outputPath": "../API/wwwroot",
"index": "src/index.html",
"main": "src/main.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.app.json",
"aot": true,
"assets": [
"src/favicon.ico",
"src/assets"
],
"styles": [
"src/styles.scss"
],
"scripts": []
},
"configurations": {
"production": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
}
],
"optimization": true,
"outputHashing": "all",
"sourceMap": false,
"extractCss": true,
"namedChunks": false,
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": true,
"budgets": [
{
"type": "initial",
"maximumWarning": "2mb",
"maximumError": "5mb"
},
{
"type": "anyComponentStyle",
"maximumWarning": "6kb",
"maximumError": "10kb"
}
]
}
}
}
Environment.ts in my Angular project
export const environment = { production: false, apiUrl: 'https://localhost:5001/api/' };
I fixed my problem. Here is what I did.
added this line to Configure() in Startup.cs
app.UseStaticFiles();
Removed
.RequireAuthorization() from
endpoints.MapControllers().RequireAuthorization();
Now it's working fine, running my Ng app from wwwroot in my API project
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.