我正在尝试使用OWIN和带有JSON Web令牌的OAuth2中间件来实现一个(自托管)OAuth2授权服务器,该中间件必须在单声道上运行 - 基本上跟随this博客帖子 - 到目前为止没有成功。我尝试使用Microsoft.Owin.Security.OAuth
方法以及IdentityServer3,无法在Windows和Linux上使用mono 4提供令牌(后者使用mono:onbuild
泊坞窗图像)。使用.NET运行时启动时,一切都按预期工作。
现在我真的想知道我是否忘记了一些非常简单的事情(因为似乎没有其他人在网上遇到这个问题),或者是否真的发生了一些错误。
虽然WebAPI路由执行在.NET 4.5和单声道4上都有效,但对oauth2/token
端点的任何访问都会以500 Internal Server Error
静默失败,即没有正文并且没有任何错误信息。对于运行minimal self-hosted示例的IdentityServer,在单声道上运行时,HTTPS端点甚至不会接受连接。当改为配置为允许HTTP时,它首先失败,如上所述的静默500
(看起来是同样的错误),然后在第二次调用时基本上爆炸为"未初始化"每次访问都有例外。
一般来说,回复只是
StatusCode: 500, ReasonPhrase: 'Internal Server Error', Version: 1.1, Content: System.Net.Http.StreamContent, Headers:
{
Server: Mono-HTTPAPI/1.0
Date: Thu, 03 Sep 2015 22:32:58 GMT
Connection: close
Content-Length: 0
}
我将完整的源代码发送到GitHub here以获取OAuth2中间件(auth
项目)和here以获取IdentityServer3方法(is3
项目,我做了降级到稳定的NuGet包;它在上面链接的样本中的预发布上 - 虽然它没有改变任何东西)。在Linux上,两者都是使用docker shell脚本构建的(构建一个脚本,然后运行一个脚本)。在Windows上,它们是使用针对.NET 4.5的Visual Studio 2015构建的,然后使用mono 4.0运行。
Startup
配置是基线,如blog post,
public void Configuration([NotNull] IAppBuilder appBuilder)
{
var config = new HttpConfiguration();
var encryptionKey = "my super secret encryption key";
appBuilder.UseAesDataProtectorProvider(encryptionKey);
config.MapHttpAttributeRoutes();
appBuilder.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
ConfigureOAuth(appBuilder);
appBuilder.UseWebApi(config);
}
public void ConfigureOAuth([NotNull] IAppBuilder appBuilder)
{
var serverOptions = new OAuthAuthorizationServerOptions
{
ApplicationCanDisplayErrors = true,
AllowInsecureHttp = true,
AuthorizeEndpointPath = new PathString("/oauth2/authorize"),
TokenEndpointPath = new PathString("/oauth2/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(30),
Provider = new CustomOAuthProvider(),
AccessTokenFormat = new CustomJwtFormat("foobar")
};
appBuilder.UseOAuthAuthorizationServer(serverOptions);
}
其中UseAesDataProtectorProvider()
调用用于替换Linux上不存在的默认DPAPI。
在CustomOAuthProvider
中,ValidateClientAuthentication()
方法只是使用
string clientId;
string clientSecret;
if (!context.TryGetBasicCredentials(out clientId, out clientSecret))
{
context.TryGetFormCredentials(out clientId, out clientSecret);
}
然后最终调用context.Validated()
或context.Rejected()
。这个调用在.NET和mono上都成功。
在GrantResourceOwnerCredentials()
中,最终使用
var identity = new ClaimsIdentity("JWT");
identity.AddClaim(new Claim(ClaimTypes.Name, context.UserName));
identity.AddClaim(new Claim("sub", context.UserName));
identity.AddClaim(new Claim(ClaimTypes.Role, "Manager"));
identity.AddClaim(new Claim(ClaimTypes.Role, "Supervisor"));
var props = new AuthenticationProperties(
new Dictionary<string, string>
{
{
"audience", context.ClientId ?? string.Empty asserten!
}
});
var ticket = new AuthenticationTicket(identity, props);
context.Validated(ticket);
此调用在.NET和mono上都能成功。
通过在整个课程中放置Console.WriteLines(...)
,我设法追踪CustomOAuthProvider.TokenEndpoint()
和CustomOAuthProvider.TokenEndpointResponse()
之间发生的问题,后者只在.NET上输入。< / p>
我错过了一些明显的东西吗?