我们有一个 ASP.NET MVC 应用程序,可以毫无问题地针对 IdentityServer3 进行身份验证,但是,如果用户在大约 3 分钟后继续使用 AJAX 功能之前等待(3 分钟之前一切似乎都很好),则使用 ApiController 的应用程序的 Web API 部分就会开始失败).
Chrome 中出现的错误是:
XMLHttpRequest 无法加载 https://test-auth.myauthapp.com/auth/connect/authorize?client_id=ecan-farmda…gwLTk5ZjMtN2QxZjUyMjgxNGE4MDg2NjFhZTAtOTEzNi00MDE3LTkzNGQtNTc5ODAzZTE1Mzgw。 请求中不存在“Access-Control-Allow-Origin”标头 资源。因此不允许来源“http://test.myapp.com” 访问。
在 IE 上我收到以下错误:
SCRIPT7002:XMLHttpRequest:网络错误0x4c7,操作是 被用户取消。
查看 IdentityServer3 的日志,我看到如下条目:
2015-08-10 16:42 [警告] (Thinktecture.IdentityServer.Core.Configuration.Hosting.CorsPolicyProvider) 对路径发出的 CORS 请求:/connect/authorize 来自源: http://test.myapp.com 但因 CORS 路径无效而被拒绝
在 IdentityServer3 Web 应用程序中,我为客户端提供AllowedCorsOrigins:
Thinktecture.IdentityServer.Core.Models.Client client = new Thinktecture.IdentityServer.Core.Models.Client()
{
Enabled = configClient.Enabled,
ClientId = configClient.Id,
ClientName = configClient.Name,
RedirectUris = new List<string>(),
PostLogoutRedirectUris = new List<string>(),
AllowedCorsOrigins = new List<string>(),
RequireConsent = false, // Don't show consents screen to user
RefreshTokenExpiration = Thinktecture.IdentityServer.Core.Models.TokenExpiration.Sliding
};
foreach (Configuration.RegisteredUri uri in configClient.RedirectUris)
{
client.RedirectUris.Add(uri.Uri);
}
foreach (Configuration.RegisteredUri uri in configClient.PostLogoutRedirectUris)
{
client.PostLogoutRedirectUris.Add(uri.Uri);
}
// Quick hack to try and get CORS working
client.AllowedCorsOrigins.Add("http://test.myapp.com");
client.AllowedCorsOrigins.Add("http://test.myapp.com/"); // Don't think trailing / needed, but added just in case
clients.Add(client);
注册服务时,我添加一个 InMemoryCorsPolicyService:
app.Map("/auth", idsrvApp =>
{
var factory = new IdentityServerServiceFactory();
factory.Register(new Registration<AuthContext>(resolver => AuthObjects.AuthContext));
factory.Register(new Registration<AuthUserStore>());
factory.Register(new Registration<AuthRoleStore>());
factory.Register(new Registration<AuthUserManager>());
factory.Register(new Registration<AuthRoleManager>());
// Custom user service used to inject custom registration workflow
factory.UserService = new Registration<IUserService>(resolver => AuthObjects.AuthUserService);
var scopeStore = new InMemoryScopeStore(Scopes.Get());
factory.ScopeStore = new Registration<IScopeStore>(scopeStore);
var clientStore = new InMemoryClientStore(Clients.Get());
factory.ClientStore = new Registration<IClientStore>(clientStore);
var cors = new InMemoryCorsPolicyService(Clients.Get());
factory.CorsPolicyService = new Registration<ICorsPolicyService>(cors);
...
var options = new IdentityServerOptions
{
SiteName = "Authentication",
SigningCertificate = LoadCertificate(),
Factory = factory,
AuthenticationOptions = authOptions
};
...
});
我确实注意到 IdentityServer3 日志条目显示“针对路径发出的 CORS 请求:/connect/authorize”,而不是“针对路径发出的 CORS 请求:/auth/connect/authorize”。但查看 IdentityServer3 源代码表明这可能不是问题所在。
也许 InMemoryCorsPolicyService 没有被拾取?
对于为什么 AJAX 的 ApiController 不起作用有什么想法吗?
Thinktecture.IdevtityServer3 v1.6.2 已使用 NuGet 安装。
更新
我正在与 IdentityServer3 开发人员进行对话,但仍有问题需要解决。如果有帮助:
https://github.com/IdentityServer/IdentityServer3/issues/1697
您是否也尝试添加 https url?- client.AllowedCorsOrigins.Add("https://test.myapp.com");
IdentityServer的文档说你应该在客户端配置它:
AllowedCorsOrigins = ... // 默认为发现、用户信息、令牌和撤销端点。
https://docs.duendesoftware.com/identityserver/v6/reference/options/#cors
CORS 是一场噩梦! 这是浏览器的问题,这就是为什么您在 IE 中看到的行为与在 Chrome 中不同的原因。
在服务器上配置 CORS 的方式(至少)有两种。当客户端发出带有
Origin
标头的请求时,您必须告诉服务器是否接受它 - 如果接受,服务器会将 Access-Control-Allow-Origin
标头添加到浏览器的响应中。
在 MVC / webAPI 中,您必须添加 CORS 服务,设置 CORS 策略,然后
.UseCors
类似这样:
builder.Services.AddCors((options =>
{
if (settings.AllowedCorsOrigins.Length > 0)
{
options.AddDefaultPolicy(builder =>
{
builder.SetIsOriginAllowedToAllowWildcardSubdomains();
builder.AllowAnyHeader().AllowAnyMethod().WithOrigins(settings.AllowedCorsOrigins);
});
}
if (isDevelopment)
{
options.AddPolicy("localhost", builder =>
{
builder.SetIsOriginAllowedToAllowWildcardSubdomains();
builder.AllowAnyHeader().AllowAnyMethod().SetIsOriginAllowed((string origin) => { return origin.Contains("localhost"); }); });
}
});
和
app.UseCors();
if (app.Environment.IsDevelopment())
{
app.UseCors("localhost");
}
通常,您希望将允许的主机列表作为字符串数组保存在
appsettings.json
中。并用 SetIsOriginAllowedToAllowWildcardSubdomains
提防陷阱。
除此之外,IdentityServer 还有自己的附加 CORS 设置,这些设置此外应用于标准 MVC/webAPI 设置。这些位于
ClientCorsOrigin
表中,并且不支持通配符子域。您可以通过实现自己的ICorsPolicyService
来避开整个陷阱,以使用与您的appsettings.json
类似的设置
public class CorsPolicyService : ICorsPolicyService
{
private readonly CorsOptions _options;
public CorsPolicyService(IOptions<CorsOptions> options)
{
_options = options.Value;
}
private bool CheckHost(string host)
{
foreach (string p in _options.AllowedCorsOrigins)
{
if (Regex.IsMatch(host, Regex.Escape(p).Replace("\\*", "[a-zA-Z0-9]+"))) // Hyphen?
{
return true;
}
}
return false;
}
public Task<bool> IsOriginAllowedAsync(string origin)
{
return Task.FromResult(CheckHost(origin));
}
}
要允许 Cors 策略,请将其添加到您的 Startup.cs 文件中。
代码
services.AddCors(options =>
{
options.AddDefaultPolicy(
builder =>
{
builder.WithOrigins("https://localhost:44343") //replace with your localhost
.AllowAnyHeader()
.AllowAnyMethod();
});
});