Angular 8, AzuredAD, ASP. NET ядро ​​WEP API 3.1, доступ к XMLHttpRequest в источнике 'http://localhost: 64982' заблокирован политикой CORS - PullRequest
0 голосов
/ 29 февраля 2020

Я работаю над клиентским приложением "Angular 8", аутентификация: "Azured AD", сервер / бизнес: ASP. NET Core Web API 3.1.

Создано Angular приложение используя шаблон Visual Studio 2019 Angular, следовательно, web api и angular будут работать на одном домене (localhost) и на тех же портах.

Я следовал нескольким статьям для проверки подлинности кода Azure в Angular 8 и веб-API. Аутентификация работает нормально на стороне Angular, после аутентификации, когда я пытался получить доступ к веб-API, я получаю исключение CORS. Я включил настроенный CORS на стороне Web API и попробовал несколько способов, но безрезультатно. Я провел так много часов на Google. Примечание: все там технологии являются новыми для меня. Ниже приведены настройки кода

Angular: app.module.ts


    export const protectedResourceMap: [string, string[]][] = [['https://graph.microsoft.com/v1.0/me', ['user.read']]];
    MsalModule.forRoot(
        {
        clientID: 'XXXXXXXXXXXXXXXXXXXXXX',
        authority: 'https://login.microsoftonline.com/X`enter code here`XXXXXXXXXXXXXXXXXXXXXXXX/',
        validateAuthority: true,
        redirectUri: "http://localhost:64982/",
        postLogoutRedirectUri: 'http://localhost:64982/',
        navigateToLoginRequestUrl: true,
        consentScopes: ["user.read", "https://mydomain.onmicrosoft.com/myapp/api-access"],
        protectedResourceMap: protectedResourceMap
        }),

fetch- data.component.ts

    const httpOptions = {
        headers: new HttpHeaders({
        'Access-Control-Allow-Credentials': '*',
        'Access-Control-Allow-Origin': '*',
        'Access-Control-Allow-Headers': '*',
        'Sec-Fetch-Site': 'same-none'
        })
    };

    @Component({
        selector: 'app-fetch-data',
        templateUrl: './fetch-data.component.html'
    })
    export class FetchDataComponent {
        public forecasts: WeatherForecast[];

        constructor(http: HttpClient, @Inject('BASE_URL') baseUrl: string) {
        http.get<WeatherForecast[]>(baseUrl + 'weatherforecast', httpOptions).subscribe(result => {
            this.forecasts = result;
        }, error => console.error(error));
        }
    }

ASP. NET CORE WEB API 3.1

appsettings. json

{
"ConnectionStrings": {
"DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=myapp;Trusted_Connection=True;MultipleActiveResultSets=true"
},
"AzureAd": {
"ClientId": "XXX",
"Authority": "https://login.microsoftonline.com/XX/v2.0",
"PostLogoutRedirectUri": "http://localhost:64982/",
"CallbackPath": "/signin-oidc",
"ResponseType": "code id_token",
"ClientSecret": "XX",
"TenantId": "XX",
"Audience": "XX",
"Issuer": "https://login.microsoftonline.com/XX/v2.0"
},    

"AzureGraph": {
"GraphApiResource": "https://graph.microsoft.com",
"MicrosoftLogin": "https://login.microsoftonline.com/"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*"
}

Start.up

    public void ConfigureServices(IServiceCollection services)
        {
            IdentityModelEventSource.ShowPII = true;
            services.AddCors((opt =>{
                opt.AddPolicy("CorsPolicy", builder => builder
                                .WithOrigins("http://localhost:64982", "http://localhost:64982/weatherforecast")
                                .AllowAnyMethod()
                                .AllowAnyHeader()
                                .AllowCredentials()
                            );
            }));
            services.Configure<CookiePolicyOptions>(options =>
            {
                // This lambda determines whether user consent for non-essential cookies is needed for a given request.
                options.CheckConsentNeeded = context => true;
                options.MinimumSameSitePolicy = SameSiteMode.None;
                // Handling SameSite cookie according to https://docs.microsoft.com/en-us/aspnet/core/security/samesite?view=aspnetcore-3.1
            });         
            services.AddAuthentication(auth =>
            {
                auth.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                auth.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
                auth.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
            })
            .AddCookie(options =>
            {
                options.AccessDeniedPath = "/AccessDenied";
                options.Cookie.Name = "AUTHCOOKIE";
                options.ExpireTimeSpan = new TimeSpan(365, 0, 0, 0);
                options.Cookie.SecurePolicy = CookieSecurePolicy.SameAsRequest;
                options.Cookie.SameSite = SameSiteMode.None;
            })
            .AddOpenIdConnect(opts =>
            {
                Configuration.GetSection("AzureAd").Bind(opts);
                opts.RequireHttpsMetadata = false;
                opts.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidIssuer = Configuration.GetValue<string>("AzureAd:Issuer"),
                    ValidAudience = Configuration.GetValue<string>("AzureAd:Audience"),
                    ValidateIssuer = true,
                    NameClaimType = "name",
                    RoleClaimType = "role"
                };              
            });     
            services.AddControllers();
            services.AddControllersWithViews()
                .AddFluentValidation(config => config.RegisterValidatorsFromAssemblyContaining<Startup>())
                .AddJsonOptions(options =>
                {
                    options.JsonSerializerOptions.PropertyNameCaseInsensitive = true;
                    options.JsonSerializerOptions.PropertyNamingPolicy = null;
                });
            services.AddSpaStaticFiles(configuration => { configuration.RootPath = "ClientApp/dist"; });

        }
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {   
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Error");
                // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
                //app.UseHsts();
            }    
            //app.UseHttpsRedirection();
            app.UseStaticFiles();               
            //app.UseCors(x => x.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader());
            app.UseRouting();
            app.UseCors("CorsPolicy");
            app.UseCustomExceptionHandler();    
            //app.UseHttpsRedirection();    
            app.UseAuthentication();
            app.UseAuthorization();
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllerRoute(
                    name: "default",
                    pattern: "{controller}/{action=Index}/{id?}");
            });    
            app.UseSpa(spa =>
            {
                // To learn more about options for serving an Angular SPA from ASP.NET Core,
                // see https://go.microsoft.com/fwlink/?linkid=864501

                spa.Options.SourcePath = "ClientApp";    
                if (env.IsDevelopment())
                {
                    spa.UseAngularCliServer(npmScript: "start");
                }
            });
        }

WeatherForecastController

    [Authorize]
    [ApiController]
    [Route("[controller]")]
    [EnableCors("AllowAll")]
    public class WeatherForecastController : ControllerBase
    {
        private static readonly string[] Summaries = new[]
        {
            "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
        };

        private readonly ILogger<WeatherForecastController> _logger;

        public WeatherForecastController(ILogger<WeatherForecastController> logger)
        {
            _logger = logger;
        }

        [HttpGet]
        public IEnumerable<WeatherForecast> Get()
        {
            var rng = new Random();
            return Enumerable.Range(1, 5).Select(index => new WeatherForecast
            {
                Date = DateTime.Now.AddDays(index),
                TemperatureC = rng.Next(-20, 55),
                Summary = Summaries[rng.Next(Summaries.Length)]
            })
            .ToArray();
        }
    }

***Following images are for request and response headers of Angular,Azure,Web APi authentication***

[Weatherforecast request header][1]
[Auth][2]
[Cors Error][3]
[URL working][4]


  [1]: https://i.stack.imgur.com/lAWlS.png
  [2]: https://i.stack.imgur.com/pcMWd.png
  [3]: https://i.stack.imgur.com/RxKCP.png
  [4]: https://i.stack.imgur.com/fA4HC.png

If I copy fourth image's response header Location URL to the same browser and accessed web api with no problem. After this access, sub subsequent Angular app accessing web api requests are working normally. Do not see CORS error then. Strange. If I dont access response header location URL in the browser then no links works in the angular app which touchs web api.  

Please help as this is killing my time. Your help is much appreciated.
...