1
votes

I have encountered issue with CORS policy when developing Angular 8, ASP NET Core Web Api web application. My angular app is running on http://localhost:4200 There is one service created for communication with Web Api. It looks as follows

@Injectable({
  providedIn: 'root'
})
export class AuthenticationService {

  apiUrl: string = "";
 

  constructor(private http: HttpClient) {
 
    this.apiUrl = 'https://localhost:44316';
  }

 
  login(Username: any, Password: any){  
    return this.http.post<Observable<ResultItem<AuthenticationResponse>>>(this.apiUrl + "/api/User/Authenticate", {Username: Username, Password: Password});
  }
 
}

Services is later called within component, but it is simply injected, and used with subscribe method.

 onLogin(){  
    this.authenticationService.login(this.loginFormValues.username.value, this.loginFormValues.password.value).subscribe(
       result => {}); 
  }

Web Api is running seperatly, on https://localhost:44316/ End point for the method called from Angular looks as follows:

[ApiController]
[Route("api/[controller]")]
public class UserController : ControllerBase
{
    private readonly IUserService userService;

    public UserController(IUserService userService)
    {
        this.userService = userService;
    }


    [HttpPost("Authenticate")]
    public async Task<IActionResult> Authenticate(AuthenticationModel model)
    {
        return Ok(await userService.Login(model));
    }
}

What I am most concerned about is my Startup file. So far, I have tried to change the CORS setting there, but with no successful results. Code of the Startup.cs file looks as follows.

Quick note:

Two lines of code within ConfigureServices method use some of my external functions, and their purpose is to:

  • AddSubstracture: registers all repositories as transients and registers DbContext.

  • AddApplication: registers services which are one layer above repositories as transients

Startup.cs code looks as follows

public class Startup
{
    private IServiceCollection _services;

    public Startup(IConfiguration configuration, IWebHostEnvironment environment)
    {
        Configuration = configuration;
        Environment = environment;
        SportFacilityUnitSettings = configuration.Get<SportFacilityUnitSettings>();
    }

    public IConfiguration Configuration { get; }
    public IWebHostEnvironment Environment { get; }
    public SportFacilityUnitSettings SportFacilityUnitSettings { get; }

    public void ConfigureServices(IServiceCollection services)
    {
         
        services.AddCors();
        services.AddMvc(option => option.EnableEndpointRouting = false);

        services.AddSubstructure(Configuration, Environment, SportFacilityUnitSettings);
        services.AddApplication(); 
        services.AddScoped<IPasswordHasher<User>, PasswordHasher<User>>();

        var appSettingsSection = Configuration.GetSection("AppSettings");
        services.Configure<AppSettings>(appSettingsSection);
         
        var appSettings = appSettingsSection.Get<AppSettings>();
        var key = Encoding.ASCII.GetBytes(appSettings.Secret);

        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,
                IssuerSigningKey = new SymmetricSecurityKey(key),
                ValidateIssuer = false,
                ValidateAudience = false
            };
        }); 
        services.AddControllers().AddNewtonsoftJson(options =>
            options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
        );

        services.Configure<AppSettings>(Configuration.GetSection("AppSettings"));
        services.AddHttpContextAccessor();

       
        _services = services;
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        app.UseCors(
         options => options.SetIsOriginAllowed(x => _ = true).AllowAnyMethod().AllowAnyHeader().AllowCredentials()
     );
        app.UseMvc();
        app.UseHsts();
        app.UseMiddleware<JwtMiddleware>(); 
        app.UseAuthentication();
        app.UseRouting();  
        app.UseHttpsRedirection();  
        app.UseStaticFiles();
        app.UseAuthorization();  
        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers(); 
        });

    }
}

When I hit the login button, which purpose is to send the request, I receive following error in web browser console.

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

The weirdest thing about it, is when I debug it, and set up a breakpoint in Api layer, debugger hits it, then it enters the service layer and fails somewhere inside Authentication method .

1
if it hits the API when you debug, it is certainly not a CORS issue.G-Man
Chrome tends to show that error message even for issues that are not CORS related.Tamás Szabó
How do you send the bearer token for authentication from your angular application?Tamás Szabó
@G-Man You were right, Cors error was misleading and error was related to .AsNoTracking() option when updating some data on authentication. Thank you for your support.mkvv

1 Answers

0
votes

Go to IIS where your application is hosted and check if you have set the below information right.

#Step 1 : IIS --> HTTP Response header]

IIS HTTP Response header

#Step 2 : : Setting 4 fields in your API app hosted under IIS Set IIS values

#Step 3: If the above 2 steps does not work, make sure you follow the msdn information to enable cors for your application https://docs.microsoft.com/en-us/aspnet/core/security/cors?view=aspnetcore-3.1

Step 4 : : Investigate the header information you are using in your web API and if that's allowed under your IIS setting (as mentioned in Step 1)

Step 5 : : Place a breakpoint in your authenticate method to see where and why its failing. You may get more clue from this error information as well.

Step 6 : Try enabling CrossDomain to true from your front end.

Step 7 : Try enabling https for both the application (calling application and called application)