ThreeMammals / Ocelot

.NET API Gateway
https://www.nuget.org/packages/Ocelot
MIT License
8.4k stars 1.64k forks source link

API Gateway using Ocelot - JWT Token Authentication (Asp.Net Core 2.1) #586

Closed kka-anand closed 6 years ago

kka-anand commented 6 years ago

Expected Behavior / New Feature

I've followed the below article link to authenticate API gateway using Ocelot. I use .Net core 2.1 When I run the application it API wasn't authenticated. It shows the result as NOTFOUND https://www.c-sharpcorner.com/article/building-api-gateway-using-ocelot-in-asp-net-core-part-two/

_____Start of Result____ Result:

Sending Request to /products , without token. Result : Unauthorized

Begin Auth.... End Auth....

Token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJrYW1hbCIsImp0aSI6ImU4MTViOTg2LTUwZjYtNDcwNy04OTE0LTljMDZmZTljNjRkOSIsImlhdCI6IjgvMzAvMjAxOCAyOjI1OjM3IFBNIiwibmJmIjoxNTM1NjM5MTM3LCJleHAiOjE1MzU2MzkyNTd9.HkTHZdlyPGA6EfyjjQfwPXAddYjpCPypZBhW3-m-uhU

Send Request to /products , with token. Result : NotFound

_End of Result___ Here is the code:

APIGateway

configuration.json

{ "DownstreamPathTemplate": "/api/products", "DownstreamScheme": "http", "DownstreamHostAndPorts": [ { "Host": "localhost", "Port": 9002 } ], "UpstreamPathTemplate": "/api/products", "UpstreamHttpMethod": [ "Get" ], "AuthenticationOptions": { "AuthenticationProviderKey": "TestKey", "AllowedScopes": [] } }

ProductController.cs

[Route("api/[controller]")]    
public class ProductsController : Controller
{
    [Authorize]
    [HttpGet]
    public IEnumerable<string> Get()
    {
        return new string[] { "Data-1", "Data-2" };
    }
}

Startup.cs

    public IConfigurationRoot Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        Action<ConfigurationBuilderCachePart> settings = (x) =>
        {
            x.WithMicrosoftLogging(log =>
            { 
                log.AddConsole(LogLevel.Debug);

            }).WithDictionaryHandle();
        };

        var signingKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes("Y2F0Y2hlciUyMHdvbmclMjBsb3ZlJTIwLm5ldA=="));

        var tokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuerSigningKey = true,
            IssuerSigningKey = signingKey,
            ValidateIssuer = true,
            ValidIssuer = audienceConfig["Iss"],
            ValidateAudience = true,
            ValidAudience = audienceConfig["Aud"],
            ValidateLifetime = true,
            ClockSkew = TimeSpan.Zero,
            RequireExpirationTime = true,
        };

        var authenticationProviderKey = "TestKey";

        services.AddAuthentication() 
        .AddJwtBearer(authenticationProviderKey, x =>
        {
               x.RequireHttpsMetadata = false;
               x.TokenValidationParameters = tokenValidationParameters;
        });

        services.AddOcelot(Configuration);
    }

Thanks, Anand

TomPallister commented 6 years ago

@kka-anand could you set your logging level to trace and paste the log of the request here?

kka-anand commented 6 years ago

Hi Tom,

No log has been traced thru API Gateway (port 9000), Yes, log has been captured with direct request with port 9002.

Log Details:

info: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[0] User profile is available. Using 'C:\Test\AppData\Local\ASP.NET\DataProtection-Keys' as key repository and Windows DPAPI to encrypt keys at rest. Hosting environment: Development Content root path: C:\Test\APIGtway\ProductAPI Now listening on: http://127.0.0.1:19377 Application started. Press Ctrl+C to shut down. info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] Request starting HTTP/1.1 DEBUG http://localhost:9002/ 0 info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] Request starting HTTP/1.1 GET http://localhost:9002/api/products
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] Request finished in 42.5047ms 200 info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] Route matched with {action = "Get", controller = "Products"}. Executing action ProductAPI.Controllers.ProductsController.Get (ProductAPI) info: Microsoft.AspNetCore.Authorization.DefaultAuthorizationService[2] Authorization failed. info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[3] Authorization failed for the request at filter 'Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter'. info: Microsoft.AspNetCore.Mvc.ChallengeResult[1] Executing ChallengeResult with authentication schemes (). info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] Executed action ProductAPI.Controllers.ProductsController.Get (ProductAPI) in 198.1231ms fail: Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware[1] An unhandled exception has occurred while executing the request. System.InvalidOperationException: No authenticationScheme was specified, and there was no DefaultChallengeScheme found. at Microsoft.AspNetCore.Authentication.AuthenticationService.ChallengeAsync(HttpContext context, String scheme, AuthenticationProperties properties) at Microsoft.AspNetCore.Mvc.ChallengeResult.ExecuteResultAsync(ActionContext context) at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeResultAsync(IActionResult result) at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeAlwaysRunResultFilters() at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeFilterPipelineAsync() at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeAsync() at Microsoft.AspNetCore.Builder.RouterMiddleware.Invoke(HttpContext httpContext) at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.Invoke(HttpContext context) info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] Request finished in 1451.2547ms 500 application/json

Thanks, Anand

TomPallister commented 6 years ago

@kka-anand I dont understand this log, it doesnt look like it comes from Ocelot?

In your case NotFound either means Ocelot cannot find a ReRoute that matches your request or your downstream service not match the route Ocelot is requesting.