Ошибка CORS с MSAL, Angular и ASP. NET Core - PullRequest
0 голосов
/ 06 января 2020

Я пытаюсь создать веб-сайт ASP. NET Core webapi + Angular, где пользователи могут войти в систему, используя личную, рабочую или учебную электронную почту Microsoft. Я следовал инструкциям, описанным здесь: https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-angular/README.md

Но учтите эту проблему,

  1. Загрузка веб-сайта angular и защищенный компонент дома страница запускает процедуру входа в систему
  2. Появляется веб-сайт Microsoft
  3. Я вхожу
  4. Браузер загружает следующий URL: https://localhost: 44321 / # id_token = ... & state = ...
  5. Веб-сайт снова загружается (второй раз после входа в систему)
  6. И я вижу следующую ошибку

    Доступ к XMLHttpRequest в 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id=... '(перенаправлено из' https://localhost: 44321 / Environment / GetUserInfo ') из источника' https://localhost: 44321 'заблокировано политикой CORS: Ответ на предварительный запрос не проходит проверку контроля доступа: Нет' Access- Заголовок Control-Allow-Origin 'присутствует в запрошенном ресурсе.

при локальной отладке с Visual Studio 2019 16.4.2 и chrome 79.0.3945.88

Any идея? Спасибо

Я создал свой проект с использованием

dotnet new angular -o myapp

И создал регистрацию приложения в Azure. Портал Аутентификация с использованием следующего URI перенаправления

  • https://localhost: 44321 / signin-microsoft
  • https://login.microsoftonline.com/
  • http://localhost: 30662 /
  • https://localhost: 44321 / signin-oid c
  • https://localhost: 44321 /

Проверены все «Предлагаемые URI перенаправления для клиентов publi c» URL выхода из системы: https://localhost: 44321 / signout-callback-oid c Неявное предоставление: токены доступа и токены ID Поддержка Live SDK: Да Тип клиента по умолчанию: Нет

Сертификат и Секрет Я создал клиентский секрет, потому что я пытался использовать провайдера Microsoft (см. Прокомментированный код ниже), а затем пытался с AzureAd

API Permission Microsoft.Graph User.Read

Предоставление API Scope = [URI идентификатора приложения] / access_as_user, только для администраторов Клиентское приложение = [CLIENT_ID_FROM_AZURE_PORTAL], область действия выше

Сторона сервера appsettings. json

 "AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "Domain": "[Application ID URI]",
    "ClientId": "[CLIENT_ID_FROM_AZURE_PORTAL]",
    "TenantId": "common",
    "CallbackPath": "/signin-oidc"
  },

Startup.cs

public void ConfigureServices(IServiceCollection services)
{
  services.AddCors(options =>
  {
    options.AddPolicy("AllowAllOrigins",
        builder =>
        {
          builder
            .AllowAnyMethod()
            .AllowAnyHeader()
            .AllowAnyOrigin();
        });
  });

  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;
  });

  // In production, the Angular files will be served from this directory
  services.AddSpaStaticFiles(configuration =>
  {
    configuration.RootPath = "ClientApp/dist";
  });

  //services
  //  .AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
  //  .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme)
  //  .AddMicrosoftAccount(microsoftOptions =>
  //{
  //  microsoftOptions.ClientId = "[CLIENT_ID_FROM_AZURE_PORTAL]";
  //  microsoftOptions.ClientSecret = "[CLIENT_SECRET_FROM_AZURE_PORTAL]";
  //});

  services.AddAuthentication(AzureADDefaults.AuthenticationScheme)
    .AddAzureAD(options => Configuration.Bind("AzureAd", options));

  services.Configure<OpenIdConnectOptions>(AzureADDefaults.OpenIdScheme, options =>
  {
    options.Authority = options.Authority + "/v2.0/";
    options.TokenValidationParameters.ValidateIssuer = false;
  });

  services.AddControllers(options =>
  {
    var policy = new AuthorizationPolicyBuilder()
                    .RequireAuthenticatedUser()
                    .Build();
    options.Filters.Add(new AuthorizeFilter(policy));
  })
  .SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
  app.UseCors("AllowAllOrigins");

  if (env.IsDevelopment())
  {
    app.UseDeveloperExceptionPage();
  }
  else
  {
    app.UseExceptionHandler("/Error");
    app.UseHsts();
  }

  app.UseHttpsRedirection();
  app.UseCookiePolicy();
  app.UseStaticFiles();
  if (!env.IsDevelopment())
  {
    app.UseSpaStaticFiles();
  }

  app.UseRouting();

  app.UseAuthentication();
  app.UseAuthorization();

  app.UseEndpoints(endpoints =>
  {
    endpoints.MapControllers();
  });

  app.UseSpa(spa =>
  {
    spa.Options.SourcePath = "ClientApp";

    if (env.IsDevelopment())
    {
      spa.UseAngularCliServer(npmScript: "start");
    }
  });
}

Клиентская сторона app.module.ts

...
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { MsalModule, MsalGuard, MsalInterceptor } from '@azure/msal-angular';
...
export const protectedResourceMap: [string, string[]][] = [
  ['https://localhost:44321/Environment/GetUserInfo', ['[Application ID URI]/access_as_user']],
  ['https://localhost:44321/api/Environment/GetUserInfo', ['[Application ID URI]/access_as_user']],
  ['https://graph.microsoft.com/v1.0/me', ['user.read']],
  ['https://login.microsoftonline.com/common', ['user.read']]
];

@NgModule({
  declarations: [
    AppComponent,
    NavMenuComponent,
    HomeComponent,
    CounterComponent,
    EntitySignoffComponent
  ],
  imports: [
    BrowserModule.withServerTransition({ appId: 'ng-cli-universal' }),
    HttpClientModule,
    FormsModule,
    AgGridModule.withComponents([]),
    MsalModule.forRoot({
      clientID: [CLIENT_ID_FROM_AZURE_PORTAL],
      authority: "https://login.microsoftonline.com/common",
      redirectUri: "https://localhost:44321/",
      validateAuthority: true,
      cacheLocation: "localStorage",
      storeAuthStateInCookie: false, // dynamically set to true when IE11
      postLogoutRedirectUri: "https://localhost:44321/",
      navigateToLoginRequestUrl: true,
      popUp: false,
      unprotectedResources: [ "https://login.microsoftonline.com/common" ],
      protectedResourceMap: protectedResourceMap
    }
    ),
    RouterModule.forRoot([
      { path: '', component: HomeComponent, pathMatch: 'full', canActivate: [MsalGuard] }
      { path: 'counter', component: CounterComponent, canActivate: [MsalGuard] },
    ])
  ],
  providers: [NavMenuComponent, { provide: HTTP_INTERCEPTORS, useClass: MsalInterceptor, multi: true }],

пакет. json

{
  "name": "myapp",
  "version": "0.0.0",
  "scripts": {
    "ng": "ng",
    "start": "ng serve",
    "build": "ng build",
    "build:ssr": "ng run myapp:server:dev",
    "test": "ng test",
    "lint": "ng lint",
    "e2e": "ng e2e"
  },
  "private": true,
  "dependencies": {
    "@angular/animations": "8.2.14",
    "@angular/common": "^8.2.14",
    "@angular/compiler": "8.2.14",
    "@angular/core": "^8.2.14",
    "@angular/forms": "8.2.14",
    "@angular/platform-browser": "8.2.14",
    "@angular/platform-browser-dynamic": "8.2.14",
    "@angular/platform-server": "8.2.14",
    "@angular/router": "8.2.14",
    "@azure/msal-angular": "^0.1.4",
    "@nguniversal/module-map-ngfactory-loader": "8.2.6",
    "aspnet-prerendering": "^3.0.1",
    "bootstrap": "^4.4.1",
    "core-js": "^3.6.1",
    "jquery": "3.4.1",
    "oidc-client": "^1.10.1",
    "popper.js": "^1.16.0",
    "rxjs": "^6.5.4",
    "rxjs-compat": "^6.5.4",
    "zone.js": "0.10.2"
  },
  "devDependencies": {
    "@angular-devkit/build-angular": "^0.803.21",
    "@angular/cli": "8.3.21",
    "@angular/compiler-cli": "8.2.14",
    "@angular/language-service": "8.2.14",
    "@types/jasmine": "^3.5.0",
    "@types/jasminewd2": "~2.0.8",
    "@types/node": "~13.1.2",
    "codelyzer": "^5.2.1",
    "jasmine-core": "~3.5.0",
    "jasmine-spec-reporter": "~4.2.1",
    "karma": "^4.4.1",
    "karma-chrome-launcher": "~3.1.0",
    "karma-coverage-istanbul-reporter": "^2.1.1",
    "karma-jasmine": "~2.0.1",
    "karma-jasmine-html-reporter": "^1.5.1",
    "typescript": "3.5.3"
  },
  "optionalDependencies": {
    "node-sass": "^4.13.0",
    "protractor": "~5.4.2",
    "ts-node": "~8.5.4",
    "tslint": "~5.20.1"
  }
}

Ошибка в Chrome после входа в систему

1 Ответ

1 голос
/ 10 января 2020

Насколько я понимаю, эти два официальных образца будут соответствовать вашим требованиям.

Я изменил официальную демоверсию и интегрировал ее для вас. Пожалуйста, следуйте инструкциям ниже, чтобы заставить их работать:

  1. Для стороны API. Вы можете скачать мой код здесь .

1) Перейдите на портал Azure и зарегистрируйте для него приложение Azure AD: enter image description here

2) Запишите его идентификатор приложения и создал для него секрет клиента. Введите их в appsettings.json: enter image description here

3) Вернитесь на портал Azure, откройте API, чтобы клиентская сторона могла запросить разрешение на него: enter image description here

4) Работа на стороне API завершена, вы можете запустить этот проект напрямую.

Для стороны angular вы можете получить мой код здесь .

1) Зарегистрировать приложение Azure AD для этой клиентской стороны: enter image description here

2) Добавьте разрешение для этого приложения, чтобы оно могло получить доступ к вашему бэкэнду: enter image description here enter image description here Нажмите кнопку предоставления разрешения для fini sh процесс: enter image description here Эти две демонстрации основаны на конечной точке Azure AD V2.0, которая позволяет личным учетным записям и рабочим учетным записям в школах входить в систему и выполнять некоторые действия.

3) Выполните некоторые настройки на блейде Auth, чтобы он мог получить токены, необходимые в качестве клиента publi c: enter image description here

4) Все шаги выполнены для angular стороны, npm start, чтобы запустить его, доступ к нему: http://localhost:44302/ Я проверил на своем локальном, и он отлично работает для меня: enter image description here

Если вы Не знаю, как объединить эти два приложения, пожалуйста, дайте мне знать.

...