【发布时间】:2018-04-13 13:11:55
【问题描述】:
我们目前正在与一个团队合作开发两种不同的 RestAPI。一个是我们的主系统,另一个只是一个空主机,其中注册了 IdentityServer。我们已经在主应用程序中成功配置了CORS 和飞行前OPTIONS 处理,但现在我们在IdentityServer 中处理OPTIONS(CORS 已启用并正常工作)。不幸的是,我们在令牌请求中需要一些特定的标头,并且浏览器正在发送飞行前OPTIONS 请求。每次我们这样做,我们都会得到:
The requested resource does not support HTTP method 'OPTIONS'.
在我们的 RestAPI 应用程序管道中,我们只需要创建 DelegatingHandler:
public class OptionsHttpMessageHandler : DelegatingHandler
{
protected override Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request,
CancellationToken cancellationToken)
{
if (request.Method == HttpMethod.Options)
{
var apiExplorer = GlobalConfiguration.Configuration.Services.GetApiExplorer();
var controllerRequested = request.GetRouteData().Values["controller"] as string;
var supportedMethods = apiExplorer.ApiDescriptions
.Where(d =>
{
var controller = d.ActionDescriptor.ControllerDescriptor.ControllerName;
return string.Equals(
controller, controllerRequested, StringComparison.OrdinalIgnoreCase);
})
.Select(d => d.HttpMethod.Method)
.Distinct();
if (!supportedMethods.Any())
{
return Task.Factory.StartNew(
() => request.CreateResponse(HttpStatusCode.NotFound));
}
return Task.Factory.StartNew(() =>
{
var response = new HttpResponseMessage(HttpStatusCode.OK);
return response;
});
}
return base.SendAsync(request, cancellationToken);
}
}
并在Global.asax注册:
GlobalConfiguration.Configuration.MessageHandlers.Add(new OptionsHttpMessageHandler());
我不知道如何在 IdentityServer 管道中注册它。下面是 Owin Startup 类的简化实现:
[assembly: OwinStartup(typeof(MyNamespace.IdentityServer.Host.Startup))]
namespace MyNamespace.IdentityServer.Host
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
var identityServerServiceFactory = new IdentityServerServiceFactory()
.UseInMemoryScopes(Scopes.Get())
.UseInMemoryClients(Clients.Get());
identityServerServiceFactory.UserService = new Registration<IUserService>(resolver => UserServiceFactory.Create());
app.Map("/identity", idsrvApp =>
{
idsrvApp.UseIdentityServer(new IdentityServerOptions
{
SiteName = "MyNamespace.IdentityServer",
SigningCertificate = this.LoadCertificate(),
Factory = identityServerServiceFactory
});
});
}
}
}
目前尝试过:
-
在 web.config 的
<handlers>部分设置一些 ISS 处理程序 -
我不记得我在哪里找到了这个解决方案,但有人建议执行以下操作:
- 在 IdentityServer 之前注册主机 API
- 创建一个控制器,将路由设置为我们想要劫持 OPTIONS 请求的地址(在我的情况下为
/identity/connect/token) - 添加
[HttpOptions]标记操作,返回200, OK
...但不幸的是,正如我所料,我的新控制器劫持了所有到 IdentityServer 的流量,而不仅仅是
OPTIONS请求。
更新 - 忘了提到第三个选项
- 我想出了一个可行的解决方案(我的意思几乎是因为我还没有完成)。这很简单,但是我宁愿避免使用这种方法,因为它会增加额外的工作,并且稍后会增加要维护的代码。这个想法是简单地将
IdentityServer's令牌端点包装在我们自己的端点中,以便 AJAX 只调用我们的 RestAPI。而且,正如我之前所说,我们的主机已经为CORS和飞行前OPTIONS设置好了
【问题讨论】:
-
不相关的旁注:在您的
OptionsHttpMessageHandler中使用Task.FromResult(或使用异步标记方法)而不是Task.Factory.StartNew,StartNew在这里完全没有必要(并且浪费时间和资源,即使一点点)。 -
老实说,它只是从外部网站复制粘贴的,我们只是验证了它有效。不过谢谢你的建议,我会解决的。
标签: c# asp.net cors asp.net-web-api2 identityserver3