0

I am currently learning Web API for ASP.NET 5 and therefore implemented a very simple application including user authorization / authentication with the Identity framework.

The login method of my AccountController which handles registration and login looks like this:

[HttpPost("[action]/{username};{password}")]
    public async Task<IActionResult> Login(string username, string password)
    {
        var result = await _signInManager.PasswordSignInAsync(username, password, false, lockoutOnFailure: false);

        if (result.Succeeded)
        {
            Logger.LogInformation(1, "User logged in.");
            return new HttpOkResult();
        }

        return new BadRequestResult();
    }

When I perform a login, I get a HTTP result which contains a cookie that looks like this:

Set-Cookie: .AspNet.Microsoft.AspNet.Identity.Application=CfDJ8 [...] 2XQ; path=/; httponly

I assume, the cookie contains the token I have to add to a HTTP request whenever I want to access a controller or method decorated with some sort of [Authorize] attribute.

However, I am unsure how a valid HTTP request containing this token has to look like. I have tried the following request which did not do the trick:

GET http://localhost:9466/api/videogames/GetAll HTTP/1.1
User-Agent: Fiddler
Host: localhost:9466
Authorization: bearer CfDJ8 [...] 2XQ

Maybe the following log snippet from a failed authorization might be of help:

[10.03.2016 12:44:30] Information: [Microsoft.AspNet.Hosting.Internal.HostingEngine] Request starting HTTP/1.1 GET http://localhost:9466/api/videogames/GetAll  
[10.03.2016 12:44:30] Warning: [Microsoft.AspNet.Mvc.Controllers.ControllerActionInvoker] Authorization failed for the request at filter 'Microsoft.AspNet.Mvc.Filters.AuthorizeFilter'.
[10.03.2016 12:44:30] Information: [Microsoft.AspNet.Authentication.Cookies.CookieAuthenticationMiddleware] AuthenticationScheme: Microsoft.AspNet.Identity.Application was challenged.
[10.03.2016 12:44:30] Information: [Microsoft.AspNet.Mvc.ChallengeResult] Executing ChallengeResult with authentication schemes ().
[10.03.2016 12:44:30] Information: [Microsoft.AspNet.Mvc.Infrastructure.MvcRouteHandler] Executed action VideoGameStoreWebApi.Controllers.VideoGamesController.GetAll in 0ms
[10.03.2016 12:44:30] Information: [Microsoft.AspNet.Hosting.Internal.HostingEngine] Request finished in 0ms 302 
[10.03.2016 12:44:30] Information: [Microsoft.AspNet.Hosting.Internal.HostingEngine] Request starting HTTP/1.1 GET http://localhost:9466/Account/Login?ReturnUrl=%2Fapi%2Fvideogames%2FGetAll  
[10.03.2016 12:44:30] Information: [Microsoft.AspNet.Hosting.Internal.HostingEngine] Request finished in 0ms 404 

Is there an error in how I add the token to the HTTP request or is there a more basic problem in how the identity framework handles user authorization i am not aware of?

Thanks in advance for your answers!

Kerl
  • 41
  • 1
  • 7

1 Answers1

0

Recommended way to use security in web-APIs is to use OAuth2 with bearer tokens.

The problem with your setup is that you are trying to combine forms authentication with token based authentication.

To use bearer tokens in web-API you need to setup a token service(also known as STS or Authorization Server) in your web-API or use some external token service (like google or facebook).

Setting up token service in your web-API is done as follows using asp.net identity.

PublicClientId = "self";
OAuthOptions = new OAuthAuthorizationServerOptions
{
    TokenEndpointPath = new PathString("/Token"),
    Provider = new ApplicationOAuthProvider(PublicClientId),
    AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
    AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
    // Note: Remove the following line before you deploy to production:
    AllowInsecureHttp = true
};

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

Now you can use jquery to post username and password to authorization server and get the access token.

    var loginData = {
        grant_type: 'password',
        username: self.loginEmail(),
        password: self.loginPassword()
    };

    $.ajax({
        type: 'POST',
        url: '/Token',
        data: loginData
    }).done(function (data) {
        self.user(data.userName);
        // Cache the access token in session storage.
        sessionStorage.setItem(tokenKey, data.access_token);
    }).fail(showError);

Then you can use the access token stored in session storage in subsequent calls to web-API.

var token = sessionStorage.getItem(tokenKey);
    var headers = {};
    if (token) {
        headers.Authorization = 'Bearer ' + token;
    }

    $.ajax({
        type: 'GET',
        url: '/api/values',
        headers: headers
    }).done(function (data) {
        self.result(data);
    }).fail(showError);

You can find the full sample of how to setup authentication and authorization with web-API here

rawel
  • 2,923
  • 21
  • 33
  • Thanks for your answer, it helped me out alot. Your example refers to Web API 2.2 and not for the version introduced with ASP.NET 5 but after some additional research I found this post: [link](https://stackoverflow.com/questions/29048122/token-based-authentication-in-asp-net-5-vnext/29698502#29698502) I was able to adopt this approach for my code although I'm still having trouble hooking up the password verification during a token request with the identity framwork managing the users (I'm currently not sure how to check if a given Username and Password are of an existing user) – Kerl Apr 07 '16 at 11:03