C# Web API/OWIN、信号机和;授权
我正在开发AngularJS、Web API和Signal应用程序的原型,作为VS 2013新项目的潜在起点 在这个阶段,我基本上使用VisualStudio为个人用户帐户生成的固定代码 StartUp.Auth.cs代码中有一行如下所示C# Web API/OWIN、信号机和;授权,c#,asp.net,angularjs,signalr,owin,C#,Asp.net,Angularjs,Signalr,Owin,我正在开发AngularJS、Web API和Signal应用程序的原型,作为VS 2013新项目的潜在起点 在这个阶段,我基本上使用VisualStudio为个人用户帐户生成的固定代码 StartUp.Auth.cs代码中有一行如下所示 app.UseOAuthBearerTokens(OAuthOptions); 有了这个功能,我可以将[Authorize]属性添加到控制器中,它工作得很好 顺便说一句,使用angular,我能够在JavaScript中添加一个包含令牌的标准头,如下所示 $
app.UseOAuthBearerTokens(OAuthOptions);
有了这个功能,我可以将[Authorize]属性添加到控制器中,它工作得很好
顺便说一句,使用angular,我能够在JavaScript中添加一个包含令牌的标准头,如下所示
$http.defaults.headers.common.Authorization = 'bearer ' + access_token;
然后我将SignalR添加到项目中。它支持自己版本的[Authorize]属性,但在使用Signal时无法传递自定义头。
这是浏览器端的一个限制。
文档中说您可以将令牌作为查询字符串的一部分传递。
我在JavaScript端添加了该代码。我的信号机代码现在包括这个。
我将代币作为“持票人代币”传递
this.connection = $.hubConnection("/TestHub", { useDefaultPath: false, qs: "bearer_token=" + token });
因此,我的问题是如何让OWIN在标记不再位于标题中时识别该标记。经过多次搜索,我最终添加了将令牌从querystring移动到标头中的代码。
对于我的原型,我只是在StartUp.Auth.cs的原始行上添加了一点代码 所以,现在看起来是这样的:
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions()
{
Provider = new OAuthBearerAuthenticationProvider()
{
OnRequestToken = context =>
{
if (context.Request.Path.Value.StartsWith("/TestHub"))
{
string bearerToken = context.Request.Query.Get("bearer_token");
if (bearerToken != null)
{
string[] authorization = new string[] { "bearer " + bearerToken };
context.Request.Headers.Add("Authorization", authorization);
}
}
return Task.FromResult(context);
}
}
});
// Enable the application to use bearer tokens to authenticate users
app.UseOAuthBearerTokens(OAuthOptions);
public class OAuthTokenProvider : OAuthBearerAuthenticationProvider
{
private List<Func<IOwinRequest, string>> _locations;
private readonly Regex _bearerRegex = new Regex("((B|b)earer\\s)");
private const string AuthHeader = "Authorization";
/// <summary>
/// By Default the Token will be searched for on the "Authorization" header.
/// <para> pass additional getters that might return a token string</para>
/// </summary>
/// <param name="locations"></param>
public OAuthTokenProvider(params Func<IOwinRequest, string>[] locations)
{
_locations = locations.ToList();
//Header is used by default
_locations.Add(x => x.Headers.Get(AuthHeader));
}
public override Task RequestToken(OAuthRequestTokenContext context)
{
var getter = _locations.FirstOrDefault(x => !String.IsNullOrWhiteSpace(x(context.Request)));
if (getter != null)
{
var tokenStr = getter(context.Request);
context.Token = _bearerRegex.Replace(tokenStr, "").Trim();
}
return Task.FromResult<object>(null);
}
}
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions
{
Provider = new OAuthTokenProvider(
req => req.Query.Get("bearer_token"),
req => req.Query.Get("access_token"),
req => req.Query.Get("token"),
req => req.Headers.Get("X-Token"))
});
上面的代码很粗糙,但这是一个原型,所以我只是想看看它是否能像它那样工作
终于开始问这个问题了:
这是将承载令牌授权与Signal和OWIN管道集成的正确模式。我似乎找不到多少关于正确方法的好信息。我使用这样一个类:
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions()
{
Provider = new OAuthBearerAuthenticationProvider()
{
OnRequestToken = context =>
{
if (context.Request.Path.Value.StartsWith("/TestHub"))
{
string bearerToken = context.Request.Query.Get("bearer_token");
if (bearerToken != null)
{
string[] authorization = new string[] { "bearer " + bearerToken };
context.Request.Headers.Add("Authorization", authorization);
}
}
return Task.FromResult(context);
}
}
});
// Enable the application to use bearer tokens to authenticate users
app.UseOAuthBearerTokens(OAuthOptions);
public class OAuthTokenProvider : OAuthBearerAuthenticationProvider
{
private List<Func<IOwinRequest, string>> _locations;
private readonly Regex _bearerRegex = new Regex("((B|b)earer\\s)");
private const string AuthHeader = "Authorization";
/// <summary>
/// By Default the Token will be searched for on the "Authorization" header.
/// <para> pass additional getters that might return a token string</para>
/// </summary>
/// <param name="locations"></param>
public OAuthTokenProvider(params Func<IOwinRequest, string>[] locations)
{
_locations = locations.ToList();
//Header is used by default
_locations.Add(x => x.Headers.Get(AuthHeader));
}
public override Task RequestToken(OAuthRequestTokenContext context)
{
var getter = _locations.FirstOrDefault(x => !String.IsNullOrWhiteSpace(x(context.Request)));
if (getter != null)
{
var tokenStr = getter(context.Request);
context.Token = _bearerRegex.Replace(tokenStr, "").Trim();
}
return Task.FromResult<object>(null);
}
}
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions
{
Provider = new OAuthTokenProvider(
req => req.Query.Get("bearer_token"),
req => req.Query.Get("access_token"),
req => req.Query.Get("token"),
req => req.Headers.Get("X-Token"))
});
然后,以下类型的请求将使其令牌未加密,以便与身份验证和授权一起使用:
GET https://www.myapp.com/authorized/endpoint?bearer_token=123ABC HTTP/1.1
GET https://www.myapp.com/authorized/endpoint?access_token=123ABC HTTP/1.1
GET https://www.myapp.com/authorized/endpoint?token=123ABC HTTP/1.1
GET https://www.myapp.com/authorized/endpoint HTTP/1.1
X-Token: 123ABC
GET https://www.myapp.com/authorized/endpoint HTTP/1.1
Authorization: 123ABC
我就是这样解决的
var authData = localStorageService.get('authorizationData');
var token = authData.token;
$.signalR.ajaxDefaults.headers = { Authorization: "Bearer " + token };
服务器端代码没有更改
希望它能帮助一些人我将为将来会出现此问题的人发布此消息: 有多种方法可以做到这一点,但这取决于应用程序的用途
signal
与头一起工作,这似乎很容易实现:
$.signal.ajaxDefaults.headers={授权:“承载人”+令牌}代码>
signar
使用longPolling
,这是您最肯定不想要的,因为您使用的是signar
查询字符串
登录时收到的访问令牌
传递给客户端。然后,创建一个自定义的属性
,该属性继承属性
()查询字符串
传递的方法是创建一个OAuth提供者
并
从管道早期的标记中检索所有其他值
同样,此方法不是最佳方法,因为查询字符串
非常容易受到攻击:
查询字符串往往存储在web服务器日志中(或在
其他方法(即使在使用SSL时)。有人的危险
拦截代币。你需要选择一种适合你的方法
情况最好
signer
管道,使用OAuth承载令牌身份验证signer
OAuthBearerTokenAuthenticationProvider
类,该类继承自OAuthBeareAuthenticationProvider
,并重写了RequestToken
方法
现在它查找存储BearerToken
的cookie并检索其值。然后,它将context.Token
设置为cookie的值
然后,在JavaScript部分,您必须获取令牌(通过使用用户名和密码进行身份验证),并将令牌存储在cookie中
public class OAuthBearerTokenAuthenticationProvider : OAuthBearerAuthenticationProvider
{
public override Task RequestToken(OAuthRequestTokenContext context)
{
var tokenCookie = context.OwinContext.Request.Cookies["BearerToken"];
if (!String.IsNullOrEmpty(tokenCookie))
context.Token = tokenCookie;
return Task.FromResult<object>(null);
}
}
公共类OAuthBearerTokenAuthenticationProvider:OAuthBeareAuthenticationProvider
{
公共覆盖任务RequestToken(OAuthRequestTokenContext上下文)
{
var tokenCookie=context.OwinContext.Request.Cookies[“BearerToken”];
如果(!String.IsNullOrEmpty(tokenCookie))
context.Token=tokenCookie;
返回Task.FromResult(空);
}
}
对于工作样本,请查看上面的回购协议
祝你好运 现在能用吗?这可能是我见过的最好的尝试,效果很好。只是知道如何去做的指导太少了。谢谢。我做了一些类似的事情,但我已经把它包装在了OWIN中间件模块中。奇怪的是,设置头对我没有任何帮助。。。我必须把cookie值放到上下文中。。。如果(!string.IsNullOrEmpty(bearerToken)){context.Token=bearerToken;}+1您能再显示一点代码吗,特别是配置/启动代码和客户端?这有帮助吗?对于使用signar的js客户端,我认为它类似于:
jQuery.hubConnection(url,{qs:“access_token=“+token})
@calebboyd+1谢谢,这正是我想要的。如何准确设置X-Token
或Authorization
头?在令牌端点的响应处理程序中,设置默认头。。。