C# Web API/OWIN、信号机和;授权

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中添加一个包含令牌的标准头,如下所示 $

我正在开发AngularJS、Web API和Signal应用程序的原型,作为VS 2013新项目的潜在起点

在这个阶段,我基本上使用VisualStudio为个人用户帐户生成的固定代码

StartUp.Auth.cs代码中有一行如下所示

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时)。有人的危险 拦截代币。你需要选择一种适合你的方法 情况最好

  • 我目前正在尝试实现的解决方案(并将在运行后更新:D)是通过将令牌通过cookie传递到
    signer
    管道,使用
    OAuth承载令牌身份验证
    signer
  • 我相信这是一个折衷最少的解决方案,但一旦我的实现完成,我会提供更多信息

    希望这有帮助。祝你好运

    更新 通过将令牌存储在cookie中,然后在提供者中检索它,我成功地使WebApi令牌身份验证与SignalR一起工作

    你可以拿一个,但我主要是按照上面的文章。明确地说,我是这样做的:

    我创建了一个
    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
    头?在令牌端点的响应处理程序中,设置默认头。。。