简体   繁体   中英

RestSharp with JWT-authentication doesn't work

This is the page where I "learned" how to do it: https://stormpath.com/blog/token-authentication-asp-net-core

But for me this is not working (doesn't work with Fiddler, too) There is this controller for my ApplicationUser-model:

[Authorize] //works when it's not set, doesn't work when it's set
[Route("api/[controller]")]
public class ApplicationUserController : Controller
{
    private IRepository<ApplicationUser> _applicationUserRepository;

    public ApplicationUserController(IRepository<ApplicationUser> applicationUserRepository)
    {
        _applicationUserRepository = applicationUserRepository;
    }

    [HttpGet("{id}")]
    public ApplicationUser Get(int id)
    {
        return _applicationUserRepository.Get(id);
    }
}

and there's my wrapper for RestSharp to get all applicationusers:

public Task<T> GetResponseContentAsync<T>(string resource, int id) where T : new()
{
    RestRequest request = new RestRequest($"{resource}/{{id}}", Method.GET);
    request.AddUrlSegment("id", id);
    if (!AuthenticationToken.IsNullOrEmpty(true))
    {
        request.AddHeader("Authorization", string.Format("Bearer {0}", AuthenticationToken));
        _client.Authenticator = new JwtAuthenticator(AuthenticationToken);
        _client.Authenticator.Authenticate(_client, request);
    }

    TaskCompletionSource<T> tcs = new TaskCompletionSource<T>();
    _client.ExecuteAsync<T>(request, response =>
    {
        tcs.SetResult(response.Data);
    });
    return tcs.Task;
}

From my web-client application I want to login with JWT (Token-Authentication) what works. After login I get eg this access_token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJURVNUIiwianRpIjoiZTBjYjE0NjgtYzBmOS00ZTM4LTg4ZjgtMGM4ZjNmYjMyNjZmIiwiaWF0IjoxNDcwOTUwMTA0LCJuYmYiOjE0NzA5NTAxMDQsImV4cCI6MTQ3MDk1MDQwNCwiaXNzIjoiRXhhbXBsZUlzc3VlciIsImF1ZCI6IkV4YW1wbGVBdWRpZW5jZSJ9.a9_JK2SG3vzc6NSOB0mZXqHlM9UAEXUHHrrijAQUsX0

without the Authorize -attribute I get the ApplicationUser, but when setting the Attribute, the result is null (since the web-api is not getting called)

the wrapper-call looks like this:

//this works, token-value is set
string token = new RepositoryCall("http://localhost:54008/").Login("token", "TEST", "TEST123");

string accessToken = JsonConvert.DeserializeObject<Dictionary<string, string>>(token)["access_token"];
ViewData["Result"] = accessToken;

ApplicationUser userAfterLogin = await new RepositoryCall("http://localhost:54008/api") 
    { AuthenticationToken = accessToken }
    .GetResponseContentAsync<ApplicationUser>("ApplicationUser", 2);

and here userAfterLogin is null.

I'm trying to get the login since two weeks but I still don't get it right..

Any idea what I'm doing wrong? Maybe a wrong request-header-value for authorization?

Update

this is my Startup.Configure where I configured to use the Bearer / JWT:

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    loggerFactory.AddConsole(Configuration.GetSection("Logging"));
    loggerFactory.AddDebug();

    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
        app.UseDatabaseErrorPage();
        app.UseBrowserLink();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
    }

    app.UseStaticFiles();

    app.UseIdentity();
    var secretKey = "mysupersecret_secretkey!123";
    var signingKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(secretKey));

    // Add external authentication middleware below. To configure them please see http://go.microsoft.com/fwlink/?LinkID=532715
    var options = new TokenProviderOptions
    {
        Audience = "ExampleAudience",
        Issuer = "ExampleIssuer",
        SigningCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256),
    };


    var tokenValidationParameters = new TokenValidationParameters
    {
        // The signing key must match!
        ValidateIssuerSigningKey = true,
        IssuerSigningKey = signingKey,

        // Validate the JWT Issuer (iss) claim
        ValidateIssuer = true,
        ValidIssuer = "ExampleIssuer",

        // Validate the JWT Audience (aud) claim
        ValidateAudience = true,
        ValidAudience = "ExampleAudience",

        // Validate the token expiry
        ValidateLifetime = true,

        // If you want to allow a certain amount of clock drift, set that here:
        ClockSkew = TimeSpan.Zero
    };


    app.UseJwtBearerAuthentication(new JwtBearerOptions
    {
        AutomaticAuthenticate = true,
        AutomaticChallenge = true,
        TokenValidationParameters = tokenValidationParameters
    });

    app.UseCookieAuthentication(new CookieAuthenticationOptions
    {
        AutomaticAuthenticate = true,
        AutomaticChallenge = true,
        AuthenticationScheme = "Cookie",
        CookieName = "access_token",
        TicketDataFormat = new CustomJwtDataFormat(
            SecurityAlgorithms.HmacSha256,
            tokenValidationParameters)
    });

    app.UseMiddleware<TokenProviderMiddleware>(Options.Create(options));
    app.UseMvc(routes =>
    {
        routes.MapRoute(
            name: "default",
            template: "{controller=Home}/{action=Index}/{id?}");
    });
}

If you recive authorizacion error or using postman you realize that you are being asked to redirect to login just decorate your class with:

[Authorize(AuthenticationSchemes = "Bearer")]

By default .Net uses cookie based auth, with that annotation you swicht to token based one

So you are using 2 middlewares for identity. One provided by asp.net identity (cookie based) and another token based. Now both of the middleware use the same attribute for handling the request [Authorize]. More precisely look at the code here

https://github.com/aspnet/Security/blob/dev/src/Microsoft.AspNetCore.Authentication.JwtBearer/JwtBearerHandler.cs

for JWTBearer

and

https://github.com/aspnet/Security/blob/dev/src/Microsoft.AspNetCore.Authentication.Cookies/CookieAuthenticationHandler.cs

for Cookie

Because both are activated in middleware pipeline the principal will have the data when you send auth token or cookie.

But because both of them are active either of them will return Unauthorized for the request that doesnt have cookie or JwtBearer.

For the solution you are looking for you need to create a middleware on top of existing cookie and token based to route the request to either based on if authorization header is present.

In Fiddler you would see, if you are redirected to login page (it would report 2 Results, one with 302 (redirect) and then the 404 - is that the case?

You have DebugLogger activated, so try AddDebug(LogLevel.Trace) and view the Debug output window, it is very helpful in analysing which of authentication steps fail. It also shows if authentication fails or authorization, and if has a valid token etc. So it points to the direction to look for problems.

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