IdentityServer 4 2.0 userInfo" No' Access-Control-Allow-Origin'标头出现在请求的资源上。"

时间:2017-11-04 05:19:00

标签: cors identityserver4 asp.net-core-2.0

情景。

在开发机器上运行本地时一切正常。但是当CI部署到开发服务器时,我们会遇到以下问题。

网站正确重定向到登录,登录成功后,我被重定向回客户端回调页面,该页面更新状态,然后尝试通过userManager.getUser()加载用户 这导致以下结果:

错误消息:

无法加载https://dev-auth.mysite.com/connect/userinfo:对预检请求的响应未通过访问控制检查:否' Access-Control-Allow-Origin'标头出现在请求的资源上。起源' https://dev-spa.mysite.com'因此不允许访问。响应的HTTP状态代码为404.

日志

从Seq Serilog我们看到以下其他呼叫成功。

请求启动HTTP / 1.1 GET http://dev-auth.mysite.com/.well-known/openid-configuration/jwks 请求启动HTTP / 1.1 GET http://dev-auth.mysite.com/.well-known/openid-configuration 请求启动HTTP / 1.1 GET http://dev-auth.mysite.com/connect/authorize/callback?client_id= ... 请求启动HTTP / 1.1 POST http://dev-auth.mysite.com/Account/Login application / x-www-form-urlencoded 643 请求启动HTTP / 1.1 GET http://dev-auth.mysite.com/account/login?returnUrl= ... 请求启动HTTP / 1.1 GET http://dev-auth.mysite.com/connect/authorize?client_id= ... 请求启动HTTP / 1.1 GET http://dev-auth.mysite.com/.well-known/openid-configuration

代码

项目是:

  • api.mysite.com
  • auth.mysite.com
  • spa.mysite.com

所有项目都是.net core 2.0。 spa项目提供使用oidc-client软件包的react应用程序。

auth.mysite.com Startup.cs

Startup的CofigureServices for Identity服务器部分是:

public void ConfigureServices(IServiceCollection aServiceCollection)
{
  // CorsPolicy.Any.Apply(aServiceCollection);
  aServiceCollection.AddMvc();
  //aServiceCollection.AddMvcCore()
  //  .AddJsonFormatters()
  //  .AddRazorViewEngine();

  aServiceCollection.AddSession();

  ConfigureServicesIdentityServer(aServiceCollection);

  aServiceCollection.Configure<RazorViewEngineOptions>(options =>
  {
    options.ViewLocationExpanders.Add(new ViewLocationExpander());
  });

  aServiceCollection.AddMediatR();
}

private static void ConfigureServicesIdentityServer(IServiceCollection aServiceCollection)
{
  aServiceCollection.AddIdentityServer()
    .AddDeveloperSigningCredential()
    .AddInMemoryApiResources(Resources.GetApiResources())
    .AddInMemoryClients(Clients.GetClients())
    .AddInMemoryIdentityResources(Resources.GetIdentityResources())
    // .AddJwtBearerClientAuthentication();
}

配置

public void Configure(
  IApplicationBuilder aApplicationBuilder,
  IHostingEnvironment aHostingEnvironment,
  IOptions<RequestLocalizationOptions> aRequestLocalizationOptions)
{
  Environment.UseExceptionPage(aHostingEnvironment, aApplicationBuilder);
  // aApplicationBuilder.UseCors(CorsPolicy.Any.DisplayName);
  aApplicationBuilder.UseIdentityServer();
  aApplicationBuilder.UseRequestLocalization(aRequestLocalizationOptions.Value);
  aApplicationBuilder.UseStaticFiles(); // Serve up static files from wwwroot images etc...
  aApplicationBuilder.UseSession();
  aApplicationBuilder.UseMvc();
}

客户端配置:

 new Client
        {
          ClientId = "someGUID",
          ClientName = "MySite",
          RequireClientSecret=false, // if false this is a public client.
          AllowedGrantTypes = GrantTypes.Implicit,
          AllowAccessTokensViaBrowser = true,
          AlwaysIncludeUserClaimsInIdToken = true,

          RedirectUris = {
            "http://local-spa.mysite.com:3000/callback",
            "https://dev-spa.mysite.com/callback",
          },
          PostLogoutRedirectUris = {
            "http://local-spa.mysite.com:3000/",
            "https://dev-spa.mysite.com/",
          },
          AllowedCorsOrigins = {
            "http://local-spa.mysite.com:3000",
            "https://dev-spa.mysite.com",
          },

          AllowedScopes =
          {
            IdentityServerConstants.StandardScopes.OpenId,
            IdentityServerConstants.StandardScopes.Profile,
            IdentityServerConstants.StandardScopes.Email,
            IdentityServerConstants.StandardScopes.Phone,
            Resources.WebOrderingApi,
          },

          RequireConsent = false,
        },

TypeScript客户端:

import { Log, OidcClientSettings, UserManager, UserManagerSettings, } from 'oidc-client';

...

const protocol: string = window.location.protocol;
const hostname: string = window.location.hostname;
const port: string = window.location.port;

const oidcClientSettings: OidcClientSettings = {
  client_id: '46a0ab4a-1321-4d77-abe5-98f09310df0b',
  post_logout_redirect_uri: `${protocol}//${hostname}${port ? `:${port}` : ''}/`,
  redirect_uri: `${protocol}//${hostname}${port ? `:${port}` : ''}/callback`,
  response_type: 'id_token token',
  scope: 'openid profile email phone WebOrderingApi',
};

const userManagerSettings: UserManagerSettings = {
  ...oidcClientSettings,
  automaticSilentRenew: false,
  filterProtocolClaims: true,
  loadUserInfo: true,
  monitorSession: false,
  silent_redirect_uri: `${protocol}//${hostname}${port ? `:${port}` : ''}/callback`,
};

更新

事实证明,开发IIS服务器不允许使用OPTIONS动词。这是在不需要CORS的生产服务器中建议做的事情,但我不建议将其用于开发环境。

感谢所有人的贡献。

IIS Request Filtering Settings

4 个答案:

答案 0 :(得分:1)

为什么这不起作用

  

对预检请求的响应没有通过访问控制检查:否&#39;访问控制 - 允许 - 来源&#39;标头出现在请求的资源上。起源&#39; https://dev-spa.mysite.com&#39;因此不允许访问。响应的HTTP状态代码为404.

在发出请求之前,会发出CORS请求,以检查是否应该允许该请求,这是使用OPTIONS方法发送的,服务器使用404响应,停止请求

如何修复

您需要发回有效的OPTIONS响应,允许请求。

我建议使用Wireshark或其他一些检查器查看发送的请求及其响应,以帮助调试CORS响应停止请求的原因。

正如@Kirk提到above,问题可能是HTTPS,无论是使用CORS请求,还是整个服务器都不支持HTTPS。

资源

答案 1 :(得分:1)

从错误消息中,我在最后注意到以下内容:

  

响应的HTTP状态代码为404.

这表明您的问题实际上可能不是CORS问题 - 可能更多的是找不到您尝试访问的端点,从而导致404响应。当然,此404响应不太可能包含相关的Access-Control-Allow-Origin标题。

查看您的日志,所有成功拨打dev-auth.mysite.com的电话都使用http方案。但是,在引用connect/userinfo端点时,您的错误消息引用了https方案:

  

无法加载 https ://dev-auth.mysite.com/connect/userinfo

答案 2 :(得分:0)

此问题的一个解决方法是允许IIS中的OPTIONS谓词用于auth服务器。

答案 3 :(得分:0)

根据文档,您可以在.NET Core CORS中混合使用,IdentityServer将兑现它。在您的Startup.cs中,添加:

public void ConfigureServices(IServiceCollection services)
{
...
    services.AddCors(options =>
    {
        options.AddPolicy("WhateverNameYouWantHere",
            builder =>
            {
                builder.WithOrigins($"http://{_frontendUri}",
                                $"https://{_frontendUri}")
                    .AllowCredentials()
                    .AllowAnyMethod()
                    .AllowAnyHeader();
            });
    });
...
}

然后再

public void Configure(IApplicationBuilder app)
{
    ...
    app.UseCors("WhateverNameYouWantHere");
}