>Background:
我有一个 ASP.NET WebAPI 项目。我正在使用持有者令牌对我的用户进行身份验证。我的一些控制器操作标有[Authorized]
过滤器。在客户端,客户端通过调用http://foo.bar/Token
然后将该令牌作为Authorization
标头添加到其请求中来获取其令牌。
到目前为止没有问题,在我的Startup.Auth.cs
类中使用这些设置,一切都可以正常工作:
OAuthOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/Token"),
Provider = new ApplicationOAuthProvider(PublicClientId),
AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
// In production mode set AllowInsecureHttp = false
AllowInsecureHttp = true
};
// Enable the application to use bearer tokens to authenticate users
app.UseOAuthBearerTokens(OAuthOptions);
现在,我已将一些 SignalR 中心添加到我的项目中,我还想对中心中的用户进行身份验证。还有一些其他问题涉及客户端如何将持有者令牌添加到 SignalR 连接。总结:
- 一种方法是将其添加为 ajax 默认标头,由于 JS WebSocket API 无法设置自定义标头,因此不鼓励这样做。因此,您回退到使用"长轮询"。(不是我想要的(
- 另一种方法是创建自定义
OAuth Provider
并将令牌作为查询字符串传递。也不鼓励使用此方法,因为它可能成为安全问题。但我仍然想使用这种方法,因为我不想要长轮询。
我尝试过:
所以我创建了这个类来从查询字符串中检索我的访问令牌。
public class QueryStringOAuthBearerProvider : OAuthBearerAuthenticationProvider
{
public override Task RequestToken(OAuthRequestTokenContext context)
{
var value = context.Request.Query.Get("access_token");
if (!string.IsNullOrEmpty(value))
{
context.Token = value;
}
return Task.FromResult<object>(null);
}
}
然后在客户端,我这样做是为了传递我的访问令牌:
var connection = $.hubConnection();
var hub = connection.createHubProxy('fooHub');
connection.qs = { 'access_token': myAccessToken};
// Init connection
这就是想法,但是当我想在Startup.Auth.cs
类中注册我的QueryStringOAuthBearerProvider
时,问题就出现了。
以下是我更改 Startup.Auth.cs 类的方式:
OAuthOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/Token"),
Provider = new ApplicationOAuthProvider(PublicClientId),
AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
// In production mode set AllowInsecureHttp = false
AllowInsecureHttp = true
};
// Enable the application to use bearer tokens to authenticate users
app.UseOAuthBearerTokens(OAuthOptions);
// Enable the application to retrieve tokens from query string to authenticate users
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions()
{
Provider = new QueryStringOAuthBearerProvider()
});
所以我想现在我可以使用:
- 默认持有者令牌,位于我的 WebAPI 调用请求的标头中。
- 我的 SignalR 中心的查询字符串中的自定义访问令牌。
结果:
当我连接到我的中心时,我可以从查询字符串中检索访问令牌,并且用户已经过身份验证。但是当我尝试调用 WebAPI 控制器操作时,我得到System.InvalidOperationException
说Sequence contains more than one element
.我认为这是因为我正在注册两种通过持有者令牌对我的用户进行身份验证的方法,而 OWIN 不喜欢这样。
问题:
如何同时使用这两种方法获取持有者令牌?
- WebAPI 调用的默认行为(授权标头(
-
QueryStringOAuthBearerProvider
(查询字符串( 的 SignalR 中心。
请注意,我不想将访问令牌作为查询字符串传递给我的 WebApi 操作,而只能传递给 SignalR 中心。
在盲目寻找答案时,我遇到了一个与我的问题有点相似的帖子,并且在评论中,一个名叫马哈茂德的人说:
我发现了问题。而不是使用
app.UseOAuthBearerTokens(OAuthOptions)
应用app.UseOAuthAuthorizationServer(OAuthOptions)
.
它在我的情况下有效,现在我可以使用这两种方法来获取持有者令牌。这是我修改后的Startup.Auth.cs
类:
OAuthOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/Token"),
Provider = new ApplicationOAuthProvider(PublicClientId),
AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
// In production mode set AllowInsecureHttp = false
AllowInsecureHttp = true
};
// Enable the application to use bearer tokens to authenticate users
//app.UseOAuthBearerTokens(OAuthOptions); // Commented this line.
app.UseOAuthAuthorizationServer(OAuthOptions); // Added this line
// Enable the application to retrieve tokens from query string to authenticate users
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions()
{
Provider = new QueryStringOAuthBearerProvider()
});
我使用了逻辑,但在QueryStringOAuthBearerProvider类中做了一些更新,然后我得到了正确的结果。
public class QueryStringOAuthBearerProvider : OAuthBearerAuthenticationProvider
{
public override Task RequestToken(OAuthRequestTokenContext context)
{
var value = context.Request.Query.Get("access_token");
if (!string.IsNullOrEmpty(value))
{
context.Token = value;
}
return Task.FromResult<object>(context);
}
}