Web API / OWIN, SignalR & Authorization

后端 未结 3 643
误落风尘
误落风尘 2021-01-30 07:29

I am developing a prototype of an AngularJS, Web API, SignalR application as a potential starting point for a new project in VS 2013.

At this stage, I\'m pretty much usi

相关标签:
3条回答
  • 2021-01-30 07:49

    This how I solved it

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

    No change on the server side code

    Hope it helps someone

    0 讨论(0)
  • 2021-01-30 07:49

    I'll post this for the the people that will have this issue in the future:

    There are multiple approaches to this in order to just make it work, but depending on the purpose of the application.

    1. The first that I've seen makes SignalR work with headers, which would seem very easy to implement:

      $.signalR.ajaxDefaults.headers = { Authorization: "Bearer " + token };

    The huge downside of this is that it forces SignalR to use longPolling, which you most definitely don't want, since you are using SignalR.

    1. The second approach is to pass the access token that the client receives when logging in as a query string, right before connecting. Then, make a custom Attribute that inherits the AuthorizeAttribute (follow this repo - not great in my opinion, but it makes a point).

    Another approach with passing the token as query string is to follow this SO answer which creates an OAuth Provider and

    retrieves all other values from the token early in the pipeline

    Again, this method is not the optimal one since query strings are pretty vulnerable:

    query strings tend to be stored in web server logs (or exposed in other ways even when using SSL). There is a risk of someone intercepting the tokens. You need to select an approach that fits your scenario best.

    1. The solution I am currently trying to implement (and will come back with updates once it works:D) is based on this blog post which uses the OAuth Bearer Token authentication with SignalR by passing the token over a cookie into SignalR pipeline.

    I believe this is the solution with the fewest compromises, but I will come back with more information once my implementation is complete.

    Hope this helps. Best of luck!

    UPDATE I managed to get WebApi token authentication to work with SignalR by storing the token in a cookie, then retrieve it in a provider.

    You cah take a look at this GitHub repo , but I mostly followed the article from above. Explicitly, here's what I did:

    I created an OAuthBearerTokenAuthenticationProvider class that inherits from OAuthBearerAuthenticationProvider and overridden the RequestToken method.

    Now it looks for the cookie where the BearerToken is stored and retrieves its value. Then, it sets the context.Token to the value of the cookie.

    Then, on the JavaScript part, you have to get the token (by authenticating using the user name and password) and store the token in a 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);
        }
    }
    

    For a working sample, please take a look at the repo above.

    Best of luck!

    0 讨论(0)
  • 2021-01-30 08:03

    I use a class like this:

    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);
        }
    }
    

    Which instead of just passing on the token to the header, parses it and sets it on the context.

    Then it could be used in your app configuration like this:

    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"))    
    });
    

    Then the following styles of requests would have their token un-encrypted, for use with authentication and authorization:

    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
    
    0 讨论(0)
提交回复
热议问题