Web API / OWIN,SignalR和授权
我正在开发AngularJS,Web API,SignalR应用程序的原型,作为VS 2013中新项目的潜在起点。
在这个阶段,我几乎使用visual studio为个人用户帐户生成的预制代码。
StartUp.Auth.cs代码中有一行看起来像这样。
app.UseOAuthBearerTokens(OAuthOptions);
有了这个,我可以将[Authorize]属性添加到控制器,它工作正常。
顺便说一句,使用angular我可以在JavaScript中添加包含令牌的标准头,如下所示。
$http.defaults.headers.common.Authorization = 'bearer ' + access_token;
然后我将SignalR添加到项目中。
它支持自己的[Authorize]属性版本,但在使用SignalR时无法传递自定义标头。
这是浏览器方面的限制。
文档说您可以将令牌作为查询字符串的一部分传递。
我在JavaScript端添加了该代码。 我的SignalR代码现在包含了这个。
我将令牌传递为’bearer_token’。
this.connection = $.hubConnection("/TestHub", { useDefaultPath: false, qs: "bearer_token=" + token });
所以我的问题是如何使OWIN识别令牌现在它不再在标题中。
经过多次搜索后,我最终添加了将令牌从查询字符串移动到标头中的代码。
对于我的原型,我刚刚在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);
上面的代码是粗略的,但这是一个原型,所以我只是想看看它是否有效。
最后回答问题:这是将承载令牌授权与SignalR和OWIN管道集成的正确模式。
我似乎无法找到正确的方法来做到这一点。
我使用这样的类:
public class OAuthTokenProvider : OAuthBearerAuthenticationProvider { private List> _locations; private readonly Regex _bearerRegex = new Regex("((B|b)earer\\s)"); private const string AuthHeader = "Authorization"; /// /// By Default the Token will be searched for on the "Authorization" header. /// pass additional getters that might return a token string /// /// public OAuthTokenProvider(params Func[] 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
而不是仅仅将令牌传递给标头,解析它并在上下文中设置它。
然后它可以在您的应用程序配置中使用,如下所示:
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")) });
然后,以下样式的请求将使其令牌未加密,以用于身份validation和授权:
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 };
服务器端代码没有变化
希望它可以帮到某人
我将为将来会遇到此问题的人发布此信息:
有多种方法可以使它工作,但取决于应用程序的目的。
-
我见过的第一个使
SignalR
与头文件SignalR
工作,这看起来很容易实现:$.signalR.ajaxDefaults.headers = { Authorization: "Bearer " + token };
这个的巨大缺点是它迫使SignalR
使用longPolling
,你绝对不想要,因为你使用的是SignalR。
- 第二种方法是在连接之前传递客户端在作为
query string
登录时收到的access token
。 然后,创建一个inheritanceAuthorizeAttribute
的自定义Attribute
( 遵循此repo – 在我看来并不是很好,但它提出了一个观点 )。
将令牌作为query string
传递的另一种方法是遵循此SO答案 , 该答案创建OAuth Provider
和
在管道的早期检索令牌中的所有其他值
同样,此方法不是最佳方法,因为query strings
非常容易受到攻击:
查询字符串往往存储在Web服务器日志中(或者即使在使用SSL时也以其他方式公开)。 有人拦截令牌的风险。 您需要选择最适合您的方案的方法。
- 我目前正在尝试实施的解决方案(并且一旦工作就会返回更新:D) 基于此博客文章 , 该文章通过将令牌通过cookie传递到
SignalR
管道,使用带有SignalR
的OAuth Bearer Token authentication
。
我相信这是最少妥协的解决方案,但是一旦我的实施完成,我会回来提供更多信息。
希望这可以帮助。 祝你好运!
更新我通过将令牌存储在cookie中,然后在提供程序中检索它,设法通过WebApi令牌身份validation来使用SignalR。
你可以看看这个GitHub回购 ,但我大多数都是按照上面的文章进行的。 明确地说,这就是我所做的:
我创建了一个OAuthBearerTokenAuthenticationProvider
类,它inheritance自OAuthBearerAuthenticationProvider
并重写了RequestToken
方法。
现在它查找存储BearerToken
的cookie并检索其值。 然后,它将context.Token
设置为cookie的值。
然后,在JavaScript部分,您必须获取令牌(通过使用用户名和密码进行身份validation)并将令牌存储在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
如需工作样本,请查看上面的回购。
祝你好运!
- 如何让Angular JS在Visual Studio 2015解决方案中工作?
- 使用angularJS和asp.net mvc下载文件
- “元素目前不可见,因此可能无法与之交互”但另一个是?
- ngcsv – 在safari和IE浏览器中遇到麻烦
- AngularJS使用Asp.net Web API:$ http post返回XMLHttpRequest无法加载:预检的响应具有无效的HTTP状态代码405
- 使用ASP.Net webapi的Angular.js $资源?
- 将Angular的请求压缩到Web API
- HttpContext.Current.Items 无效,因为AngularJS调用创建新会话
- 具有子集合的AngularJs Post Object到MVC WebAPI