asp.net Web API / OWIN、SignalR和授权

deyfvvtc  于 2023-03-31  发布在  .NET
关注(0)|答案(3)|浏览(215)

我正在开发一个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管道集成的正确模式吗?

我似乎找不到很多关于正确方法的好信息。

irtuqstp

irtuqstp1#

我使用这样一个类:

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
oprakyz7

oprakyz72#

我就是这么解决的

var authData = localStorageService.get('authorizationData');
var token = authData.token;
 $.signalR.ajaxDefaults.headers = { Authorization: "Bearer " + token };

服务器端代码没有变化
希望能帮到什么人

yc0p9oo0

yc0p9oo03#

我将张贴这一点的人,将有这个问题在未来:
有多种方法可以使其工作,但这取决于应用程序的目的。
1.我看到的第一个让SignalR可以处理头文件,这看起来很容易实现:
$.signalR.ajaxDefaults.headers = { Authorization: "Bearer " + token };
这样做的巨大缺点是它迫使SignalR使用longPolling,这是您绝对不希望的,因为您正在使用SignalR。
1.第二种方法是在连接之前传递客户端以query string登录时接收的access token。然后,创建一个继承AuthorizeAttributefollow this repo - not great in my opinion, but it makes a point)的自定义Attribute
将令牌作为query string传递的另一种方法是follow this SO answer,这将创建一个OAuth Provider
在管道早期从标记中检索所有其他值
同样,这种方法不是最佳方法,因为query strings非常脆弱:
查询字符串倾向于存储在Web服务器日志中(或以其他方式暴露,即使使用SSL)。存在有人拦截令牌的风险。您需要选择最适合您的方案的方法。
1.我目前正在尝试实现的解决方案(一旦成功,将返回更新:D)基于这篇博客文章,它通过将令牌通过cookie传递到SignalR管道中来使用OAuth Bearer Token authenticationSignalR
我相信这是妥协最少的解决方案,但是一旦我的实现完成,我会回来提供更多信息。
希望这对你有帮助,祝你好运!
更新我设法让WebApi令牌身份验证与SignalR一起工作,方法是将令牌存储在cookie中,然后在提供程序中检索它。
你可以使用look at this GitHub repo,但我主要是按照上面的文章来做的。明确地说,我是这样做的:
我创建了一个OAuthBearerTokenAuthenticationProvider类,它继承了OAuthBearerAuthenticationProvider并覆盖了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);
    }
}

对于一个工作示例,请查看上面的repo。
祝你好运!

相关问题