MSAL、Angular和ASP.NET内核的CORS错误

MSAL、Angular和ASP.NET内核的CORS错误,angular,asp.net-core,azure-active-directory,msal,msal.js,Angular,Asp.net Core,Azure Active Directory,Msal,Msal.js,我正在尝试建立一个ASP.NET核心webapi+Angular网站,用户可以使用Microsoft个人或工作或学校电子邮件登录。我按照此处描述的说明进行操作: 但是遇到这个问题, 网站加载和主页上受保护的组件触发登录过程 此时将显示microsoft网站 我登录 浏览器将加载以下url:https://localhost:44321/#id_token=...&state=... 网站重新加载(登录后第二次) 我看到了下面的错误 访问位于“”的XMLHttpRequesthttps

我正在尝试建立一个ASP.NET核心webapi+Angular网站,用户可以使用Microsoft个人或工作或学校电子邮件登录。我按照此处描述的说明进行操作:

但是遇到这个问题,

  • 网站加载和主页上受保护的组件触发登录过程

  • 此时将显示microsoft网站

  • 我登录

  • 浏览器将加载以下url:https://localhost:44321/#id_token=...&state=...

  • 网站重新加载(登录后第二次)

  • 我看到了下面的错误

    访问位于“”的XMLHttpRequesthttps://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进行本地调试时

    有什么想法吗?
    谢谢

    ...
    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 }],
    
    我已经使用

    dotnet new angular -o myapp
    
    并在Azure.Portal中创建了应用程序注册
    使用以下重定向URI进行身份验证

    • https://localhost:44321/signin-微软
    • https://login.microsoftonline.com/
    • http://localhost:30662/
    • https://localhost:44321/signin-oidc
    • https://localhost:44321/
    已检查所有“公共客户端的建议重定向URI”
    注销URL:https://localhost:44321/signout-回调oidc
    隐式授权:访问令牌和ID令牌
    Live SDK支持:是
    默认客户端类型:否

    证书和机密
    我创建了一个客户端密码,因为我尝试使用Microsoft provider(请参阅下面的注释代码),然后尝试使用AzureAd

    API权限
    Microsoft.Graph用户.Read

    公开API
    Scope=[Application ID URI]/access\u作为用户,仅限管理员
    客户端应用程序=[来自AZURE门户的客户端ID],作用域如上

    服务器端
    appsettings.json

     "AzureAd": {
        "Instance": "https://login.microsoftonline.com/",
        "Domain": "[Application ID URI]",
        "ClientId": "[CLIENT_ID_FROM_AZURE_PORTAL]",
        "TenantId": "common",
        "CallbackPath": "/signin-oidc"
      },
    
    {
      "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"
      }
    }
    
    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");
        }
      });
    }
    
    package.json

     "AzureAd": {
        "Instance": "https://login.microsoftonline.com/",
        "Domain": "[Application ID URI]",
        "ClientId": "[CLIENT_ID_FROM_AZURE_PORTAL]",
        "TenantId": "common",
        "CallbackPath": "/signin-oidc"
      },
    
    {
      "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"
      }
    }
    

    据我所知,这两个官方样品将完全满足您的要求

    我已经修改了官方演示并为您集成了它。请按照以下步骤操作,使其正常工作:

  • 对于API方面 1) 已访问Azure门户并为其注册Azure广告应用程序:

    2) 记下它的应用程序id,并为它创建一个客户端密码。将它们键入
    appsettings.json

    3) 返回Azure portal,公开API,以便客户端可以请求其权限:

    4) API端的工作已经完成,您可以直接运行此项目

  • 对于角度方面,您可以
  • 1) 为此客户端注册Azure广告应用程序:

    2) 向此应用添加权限,以便它可以访问您的后端: 单击“授予权限”按钮以完成此过程: 这两个演示都基于Azure AD V2.0端点,该端点允许个人帐户和学校工作帐户登录并执行一些操作

    3) 在Auth blade上进行一些配置,以便它可以获得作为公共客户端所需的令牌:

    4) 角度侧的所有步骤都已完成,
    npm start
    要运行它,请访问:
    http://localhost:44302/
    我在我的本地电脑上进行了测试,它非常适合我:


    如果您不知道如何组合这两个应用程序,请让我知道。

    请检查问题是否是由以下原因引起的。我已更新这些线路服务。AddAuthentication(AzureAddFaults.BeareAuthenticationScheme)。AddAzureADBearer(选项=>Configuration.Bind(“AzureAd”,选项));但是现在我得到了401,它在登录HttpErrorResponse后仍然加载了两次网页{headers:HttpHeaders,status:401,statusText:“OK”,url:,OK:false,}嗨,你的问题现在解决了吗?嗨,Stanley,没有,我有同样的问题,检查上面的图片“登录后Chrome中的错误”我尝试合并这些应用程序,但在客户端出现以下错误:错误:需要登录\u;错误描述:AADSTS50058:发送了静默登录请求,但没有用户登录。用于表示用户会话的Cookie未在Azure AD请求中发送。如果用户正在使用Internet Explorer或Edge,并且发送静默登录请求的web应用与Azure AD端点位于不同的IE安全区域,则可能会发生这种情况。我正在使用chrome,如果可能的话,你可以上传你的版本,这样我就可以排除合并作为一个潜在的问题了Hi@D2O,我已经用详细的步骤更新了我的答案,请检查Hi Stanley,很抱歉耽搁了,我按照你的步骤,但不得不做一些额外的任务;对于服务器,我必须从github克隆Microsoft.Identity.Web项目并引用它;在客户端,我必须用clientID和webapicorges更新app.js。现在,网站登录和注销,但是当我调用api时,仍然存在以下错误:在响应中获取错误:{“方法”:“POST”,“transformRequest”:[null],“transformResponse”:[null],“jsonpCallbackParam”:“回调”,“url”:":已发送静默登录请求,但未登录任何用户,但我从您的步骤中学到的一件事是,服务器和客户端有单独的注册,我不知道,我认为这是两者的一次注册。我的更改是否正确。是否可能我错过了其他内容。感谢您的帮助我添加了一个链接,其中包含m我的浏览器有错误和注销按钮