简体   繁体   中英

.NET Web API 2 OWIN Bearer Token Authentication direct call

I have a problem with my Web Api Project. I have files stored in my Database and want to call them directly in a new window to view/save (URL like : /api/Files/5 - 5 beeing the FileId)

I got everthing working with the Bearer Token for my general AJAX requests with AngularJS for normal Data and it works like a charm. For the file I created a Controller that shows the file in the browser with the corresponding MIME-Type. But now that I changed the action to [Authorize] I get an Access Denied which is correct because I didnt pass an access_token in the HTTP-Header.

I did quite some research if it is possible to pass the Token via the querystring but didn't find anything helpful.

Now my plan is to remove the [Authorize] Attribute from my Controller and try to validate the token myself but I don't know how.

Anyone know how I can get it to work?

I implemented bearer token authentication in my app (AngularJS, WebAPI 2) and I had similar problem - I needed to allow downloading files by clicking on a link. When you click on a link headers are not sent. :( So, I sent the token value in a query string to download a file

.../mywebapp/api/files/getfile/3?access_token=jaCOTrGsaak6Sk0CpPc1...

and set "Authorization" header to the token value in Startup.Auth.cs. Here is the code:

public void ConfigureAuth(IAppBuilder app)
{
    //It needs for file downloads
    app.Use(async (context, next) =>
    {
        if (context.Request.QueryString.HasValue)
        {
            if (string.IsNullOrWhiteSpace(context.Request.Headers.Get("Authorization")))
            {
                var queryString = HttpUtility.ParseQueryString(context.Request.QueryString.Value);
                string token = queryString.Get("access_token");

                if (!string.IsNullOrWhiteSpace(token))
                {
                    context.Request.Headers.Add("Authorization", new[] { string.Format("Bearer {0}", token) });
                }
            }
        }

        await next.Invoke();
    });
    // Enable the application to use bearer tokens to authenticate users
    app.UseOAuthBearerTokens(OAuthOptions);
}

For ASP .Net Core I did something like this based on Forward 's answer

Extension Method

  public static void UseQueryStringBearerValidation(this IApplicationBuilder app)
    {
        //It needs for file downloads
        app.Use(async (context, next) =>
        {
            if (context.Request.QueryString.HasValue)
            {
                if (string.IsNullOrWhiteSpace(context.Request.Headers["Authorization"].ToString()))
                {
                    var queryString = QueryHelpers.ParseQuery(context.Request.QueryString.Value);
                    var token = queryString["access_token"].ToString();

                    if (!string.IsNullOrWhiteSpace(token))
                    {
                        context.Request.Headers.Add("Authorization", new[] {$"Bearer {token}"});
                    }
                }
            }

            await next();
        });
    }

Usage

StartUp.cs -> Configure() method

            app.UseCustomExceptionHandler();
            app.UseQueryStringBearerValidation(); // <-- add before Jwt Handler
            app.UseCustomJwtBearerValidation();
            app.AddHttpContextProperties();
            app.UseStaticFiles();
            app.UseMvc(MiddlewareAppConfiguration.AddRouteMappings);

Although I'm not sure it's a very good idea, you could implementing a DelegatingHandler to achieve what you are looking for.

public class QueryStringBearerToken : DelegatingHandler
{
    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        var bearerToken = request.GetQueryNameValuePairs()
                                 .Where(kvp => kvp.Key == "bearerToken")
                                 .Select(kvp => kvp.Value)
                                 .FirstOrDefault();

        if(!String.IsNullOrEmpty(bearerToken))
        {
            request.Headers.Add("Authorization", "Bearer " + bearerToken);
        }
        return base.SendAsync(request, cancellationToken);
    }
}

This handler will look for the query string named "bearerToken" and, if it exists, will add it to the request header for the subsequent handlers / filter to process. You might want to check first if the header is already present and not override in this case. You can add this handler in your configuration phase in the usual fashion:

config.MessageHandlers.Insert(0, new QueryStringBearerToken ());

A request for /YourRoute?bearerToken=theToken will pass in the DelegatingHandler , adding the token passed in the query string to the list of headers in the original request and the regular Bearer Token authentication will look for the header and find it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM