Browse Source

Add swagger authorization option in APIs

pull/241/head
Ramón Tomás 7 years ago
parent
commit
d289ec00cf
17 changed files with 238 additions and 19 deletions
  1. +10
    -2
      docker-compose.override.yml
  2. +1
    -0
      docker-compose.yml
  3. +1
    -1
      src/Services/Basket/Basket.API/Basket.API.csproj
  4. +1
    -1
      src/Services/Basket/Basket.API/Controllers/BasketController.cs
  5. +32
    -0
      src/Services/Basket/Basket.API/Infrastructure/Filters/AuthorizeCheckOperationFilter.cs
  6. +23
    -7
      src/Services/Basket/Basket.API/Startup.cs
  7. +60
    -0
      src/Services/Identity/Identity.API/Configuration/Config.cs
  8. +4
    -0
      src/Services/Identity/Identity.API/Startup.cs
  9. +1
    -1
      src/Services/Location/Locations.API/Dockerfile
  10. +1
    -1
      src/Services/Location/Locations.API/Infrastructure/Filters/AuthorizeCheckOperationFilter.cs
  11. +3
    -3
      src/Services/Location/Locations.API/Startup.cs
  12. +32
    -0
      src/Services/Marketing/Marketing.API/Infrastructure/Filters/AuthorizeCheckOperationFilter.cs
  13. +17
    -1
      src/Services/Marketing/Marketing.API/Startup.cs
  14. +32
    -0
      src/Services/Ordering/Ordering.API/Infrastructure/Filters/AuthorizeCheckOperationFilter.cs
  15. +18
    -0
      src/Services/Ordering/Ordering.API/Startup.cs
  16. +1
    -1
      src/Services/Payment/Payment.API/Controllers/HomeController.cs
  17. +1
    -1
      src/Services/Payment/Payment.API/Dockerfile

+ 10
- 2
docker-compose.override.yml View File

@ -20,6 +20,7 @@ services:
- ASPNETCORE_URLS=http://0.0.0.0:80
- ConnectionString=${ESHOP_AZURE_REDIS_BASKET_DB:-basket.data}
- identityUrl=http://identity.api #Local: You need to open your local dev-machine firewall at range 5100-5110.
- IdentityUrlExternal=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5105
- EventBusConnection=${ESHOP_AZURE_SERVICE_BUS:-rabbitmq}
ports:
- "5103:80"
@ -44,7 +45,11 @@ services:
- SpaClient=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5104
- XamarinCallback=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5105/xamarincallback #localhost do not work for UWP login, so we have to use "external" IP always
- ConnectionStrings__DefaultConnection=${ESHOP_AZURE_IDENTITY_DB:-Server=sql.data;Database=Microsoft.eShopOnContainers.Service.IdentityDb;User Id=sa;Password=Pass@word}
- MvcClient=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5100 #Local: You need to open your local dev-machine firewall at range 5100-5110.
- MvcClient=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5100 #Local: You need to open your local dev-machine firewall at range 5100-5110.
- LocationApiClient=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5109
- MarketingApiClient=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5110
- BasketApiClient=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5103
- OrderingApiClient=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5102
- UseCustomizationData=True
ports:
- "5105:80"
@ -55,6 +60,7 @@ services:
- ASPNETCORE_URLS=http://0.0.0.0:80
- ConnectionString=${ESHOP_AZURE_ORDERING_DB:-Server=sql.data;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word}
- identityUrl=http://identity.api #Local: You need to open your local dev-machine firewall at range 5100-5110.
- IdentityUrlExternal=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5105
- EventBusConnection=${ESHOP_AZURE_SERVICE_BUS:-rabbitmq}
- UseCustomizationData=True
ports:
@ -69,6 +75,7 @@ services:
- MongoDatabase=MarketingDb
- EventBusConnection=${ESHOP_AZURE_SERVICE_BUS:-rabbitmq}
- identityUrl=http://identity.api #Local: You need to open your local dev-machine firewall at range 5100-5110.
- IdentityUrlExternal=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5105
- CampaignDetailFunctionUri=${ESHOP_AZUREFUNC_CAMPAIGN_DETAILS_URI}
- PicBaseUrl=${ESHOP_AZURE_STORAGE_MARKETING:-http://localhost:5110/api/v1/campaigns/[0]/pic/}
- AzureStorageAccountName=${ESHOP_AZURE_STORAGE_MARKETING_NAME}
@ -137,7 +144,7 @@ services:
payment.api:
environment:
- ASPNETCORE_ENVIRONMENT=Development
- ASPNETCORE_URLS=http://0.0.0.0:5108
- ASPNETCORE_URLS=http://0.0.0.0:80
- EventBusConnection=${ESHOP_AZURE_SERVICE_BUS:-rabbitmq}
ports:
- "5108:80"
@ -149,6 +156,7 @@ services:
- ConnectionString=${ESHOP_AZURE_COSMOSDB:-mongodb://nosql.data}
- Database=LocationsDb
- identityUrl=http://identity.api #Local: You need to open your local dev-machine firewall at range 5100-5110.
- IdentityUrlExternal=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5105
- EventBusConnection=${ESHOP_AZURE_SERVICE_BUS:-rabbitmq}
ports:
- "5109:80"

+ 1
- 0
docker-compose.yml View File

@ -18,6 +18,7 @@ services:
depends_on:
- basket.data
- identity.api
- rabbitmq
catalog.api:
image: eshop/catalog.api:${TAG:-latest}


+ 1
- 1
src/Services/Basket/Basket.API/Basket.API.csproj View File

@ -19,8 +19,8 @@
<ItemGroup>
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="4.1.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="1.0.0" />
<PackageReference Include="StackExchange.Redis" Version="1.2.3" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="1.0.0" />
<PackageReference Include="System.Threading" Version="4.3.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="1.1.3" />
<PackageReference Include="Microsoft.AspNetCore.Server.IISIntegration" Version="1.1.2" />


+ 1
- 1
src/Services/Basket/Basket.API/Controllers/BasketController.cs View File

@ -13,7 +13,7 @@ using Basket.API.Model;
namespace Microsoft.eShopOnContainers.Services.Basket.API.Controllers
{
[Route("/")]
[Route("api/v1/[controller]")]
[Authorize]
public class BasketController : Controller
{


+ 32
- 0
src/Services/Basket/Basket.API/Infrastructure/Filters/AuthorizeCheckOperationFilter.cs View File

@ -0,0 +1,32 @@
using Microsoft.AspNetCore.Authorization;
using Swashbuckle.AspNetCore.Swagger;
using Swashbuckle.AspNetCore.SwaggerGen;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Basket.API.Infrastructure.Filters
{
public class AuthorizeCheckOperationFilter : IOperationFilter
{
public void Apply(Operation operation, OperationFilterContext context)
{
// Check for authorize attribute
var hasAuthorize = context.ApiDescription.ControllerAttributes().OfType<AuthorizeAttribute>().Any() ||
context.ApiDescription.ActionAttributes().OfType<AuthorizeAttribute>().Any();
if (hasAuthorize)
{
operation.Responses.Add("401", new Response { Description = "Unauthorized" });
operation.Responses.Add("403", new Response { Description = "Forbidden" });
operation.Security = new List<IDictionary<string, IEnumerable<string>>>();
operation.Security.Add(new Dictionary<string, IEnumerable<string>>
{
{ "oauth2", new [] { "basketapi" } }
});
}
}
}
}

+ 23
- 7
src/Services/Basket/Basket.API/Startup.cs View File

@ -28,6 +28,8 @@ using System.Threading.Tasks;
using Microsoft.eShopOnContainers.BuildingBlocks.EventBusServiceBus;
using Microsoft.Azure.ServiceBus;
using Swashbuckle.AspNetCore.Swagger;
using System.Collections.Generic;
namespace Microsoft.eShopOnContainers.Services.Basket.API
{
@ -47,19 +49,18 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API
// This method gets called by the runtime. Use this method to add services to the container.
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.AddHealthChecks(checks =>
{
checks.AddValueTaskCheck("HTTP Endpoint", () => new ValueTask<IHealthCheckResult>(HealthCheckResult.Healthy("Ok")));
});
{
// Add framework services.
services.AddMvc(options =>
{
options.Filters.Add(typeof(HttpGlobalExceptionFilter));
}).AddControllersAsServices();
services.AddHealthChecks(checks =>
{
checks.AddValueTaskCheck("HTTP Endpoint", () => new ValueTask<IHealthCheckResult>(HealthCheckResult.Healthy("Ok")));
});
services.Configure<BasketSettings>(Configuration);
//By connecting here we are making sure that our service
@ -118,6 +119,20 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API
Description = "The Basket Service HTTP API",
TermsOfService = "Terms Of Service"
});
options.AddSecurityDefinition("oauth2", new OAuth2Scheme
{
Type = "oauth2",
Flow = "implicit",
AuthorizationUrl = $"{Configuration.GetValue<string>("IdentityUrlExternal")}/connect/authorize",
TokenUrl = $"{Configuration.GetValue<string>("IdentityUrlExternal")}/connect/token",
Scopes = new Dictionary<string, string>()
{
{ "basket", "Basket API" }
}
});
options.OperationFilter<AuthorizeCheckOperationFilter>();
});
services.AddCors(options =>
@ -185,6 +200,7 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API
.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
c.ConfigureOAuth2("basketswaggerui", "", "", "Basket Swagger UI");
});
ConfigureEventBus(app);


+ 60
- 0
src/Services/Identity/Identity.API/Configuration/Config.cs View File

@ -146,6 +146,66 @@ namespace Identity.API.Configuration
"locations",
"marketing"
},
},
new Client
{
ClientId = "locationsswaggerui",
ClientName = "Locations Swagger UI",
AllowedGrantTypes = GrantTypes.Implicit,
AllowAccessTokensViaBrowser = true,
RedirectUris = { $"{clientsUrl["LocationsApi"]}/swagger/o2c.html" },
PostLogoutRedirectUris = { $"{clientsUrl["LocationsApi"]}/swagger/" },
AllowedScopes =
{
"locations"
}
},
new Client
{
ClientId = "marketingswaggerui",
ClientName = "Marketing Swagger UI",
AllowedGrantTypes = GrantTypes.Implicit,
AllowAccessTokensViaBrowser = true,
RedirectUris = { $"{clientsUrl["MarketingApi"]}/swagger/o2c.html" },
PostLogoutRedirectUris = { $"{clientsUrl["MarketingApi"]}/swagger/" },
AllowedScopes =
{
"marketing"
}
},
new Client
{
ClientId = "basketswaggerui",
ClientName = "Basket Swagger UI",
AllowedGrantTypes = GrantTypes.Implicit,
AllowAccessTokensViaBrowser = true,
RedirectUris = { $"{clientsUrl["BasketApi"]}/swagger/o2c.html" },
PostLogoutRedirectUris = { $"{clientsUrl["BasketApi"]}/swagger/" },
AllowedScopes =
{
"basket"
}
},
new Client
{
ClientId = "orderingswaggerui",
ClientName = "Ordering Swagger UI",
AllowedGrantTypes = GrantTypes.Implicit,
AllowAccessTokensViaBrowser = true,
RedirectUris = { $"{clientsUrl["OrderingApi"]}/swagger/o2c.html" },
PostLogoutRedirectUris = { $"{clientsUrl["OrderingApi"]}/swagger/" },
AllowedScopes =
{
"orders"
}
}
};
}


+ 4
- 0
src/Services/Identity/Identity.API/Startup.cs View File

@ -163,6 +163,10 @@ namespace eShopOnContainers.Identity
clientUrls.Add("Mvc", Configuration.GetValue<string>("MvcClient"));
clientUrls.Add("Spa", Configuration.GetValue<string>("SpaClient"));
clientUrls.Add("Xamarin", Configuration.GetValue<string>("XamarinCallback"));
clientUrls.Add("LocationsApi", Configuration.GetValue<string>("LocationApiClient"));
clientUrls.Add("MarketingApi", Configuration.GetValue<string>("MarketingApiClient"));
clientUrls.Add("BasketApi", Configuration.GetValue<string>("BasketApiClient"));
clientUrls.Add("OrderingApi", Configuration.GetValue<string>("OrderingApiClient"));
using (var serviceScope = app.ApplicationServices.GetService<IServiceScopeFactory>().CreateScope())
{


+ 1
- 1
src/Services/Location/Locations.API/Dockerfile View File

@ -1,4 +1,4 @@
FROM microsoft/aspnetcore:1.1
FROM microsoft/aspnetcore:1.1.2
ARG source
WORKDIR /app
EXPOSE 80


+ 1
- 1
src/Services/Location/Locations.API/Infrastructure/Filters/AuthorizeCheckOperationFilter.cs View File

@ -23,7 +23,7 @@ namespace Microsoft.eShopOnContainers.Services.Locations.API.Infrastructure.Filt
operation.Security = new List<IDictionary<string, IEnumerable<string>>>();
operation.Security.Add(new Dictionary<string, IEnumerable<string>>
{
{ "oauth2", new [] { "api1" } }
{ "oauth2", new [] { "locationsapi" } }
});
}
}


+ 3
- 3
src/Services/Location/Locations.API/Startup.cs View File

@ -107,8 +107,8 @@ namespace Microsoft.eShopOnContainers.Services.Locations.API
{
Type = "oauth2",
Flow = "implicit",
AuthorizationUrl = "http://localhost:5105/connect/authorize",
TokenUrl = "http://localhost:5105/connect/token",
AuthorizationUrl = $"{Configuration.GetValue<string>("IdentityUrlExternal")}/connect/authorize",
TokenUrl = $"{Configuration.GetValue<string>("IdentityUrlExternal")}/connect/token",
Scopes = new Dictionary<string, string>()
{
{ "locations", "Locations API" }
@ -158,7 +158,7 @@ namespace Microsoft.eShopOnContainers.Services.Locations.API
.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
c.ConfigureOAuth2("swaggerui", "", "", "Swagger UI");
c.ConfigureOAuth2("locationsswaggerui", "", "", "Locations Swagger UI");
});
LocationsContextSeed.SeedAsync(app, loggerFactory)


+ 32
- 0
src/Services/Marketing/Marketing.API/Infrastructure/Filters/AuthorizeCheckOperationFilter.cs View File

@ -0,0 +1,32 @@
using Microsoft.AspNetCore.Authorization;
using Swashbuckle.AspNetCore.Swagger;
using Swashbuckle.AspNetCore.SwaggerGen;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.Services.Marketing.API.Infrastructure.Filters
{
public class AuthorizeCheckOperationFilter : IOperationFilter
{
public void Apply(Operation operation, OperationFilterContext context)
{
// Check for authorize attribute
var hasAuthorize = context.ApiDescription.ControllerAttributes().OfType<AuthorizeAttribute>().Any() ||
context.ApiDescription.ActionAttributes().OfType<AuthorizeAttribute>().Any();
if (hasAuthorize)
{
operation.Responses.Add("401", new Response { Description = "Unauthorized" });
operation.Responses.Add("403", new Response { Description = "Forbidden" });
operation.Security = new List<IDictionary<string, IEnumerable<string>>>();
operation.Security.Add(new Dictionary<string, IEnumerable<string>>
{
{ "oauth2", new [] { "marketingapi" } }
});
}
}
}
}

+ 17
- 1
src/Services/Marketing/Marketing.API/Startup.cs View File

@ -28,7 +28,8 @@
using System.Threading.Tasks;
using Extensions.HealthChecks;
using Marketing.API.IntegrationEvents.Handlers;
using Swashbuckle.AspNetCore.Swagger;
using System.Collections.Generic;
public class Startup
{
@ -129,6 +130,20 @@
Description = "The Marketing Service HTTP API",
TermsOfService = "Terms Of Service"
});
options.AddSecurityDefinition("oauth2", new OAuth2Scheme
{
Type = "oauth2",
Flow = "implicit",
AuthorizationUrl = $"{Configuration.GetValue<string>("IdentityUrlExternal")}/connect/authorize",
TokenUrl = $"{Configuration.GetValue<string>("IdentityUrlExternal")}/connect/token",
Scopes = new Dictionary<string, string>()
{
{ "marketing", "Marketing API" }
}
});
options.OperationFilter<AuthorizeCheckOperationFilter>();
});
services.AddCors(options =>
@ -171,6 +186,7 @@
.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
c.ConfigureOAuth2("marketingswaggerui", "", "", "Marketing Swagger UI");
});
var context = (MarketingContext)app


+ 32
- 0
src/Services/Ordering/Ordering.API/Infrastructure/Filters/AuthorizeCheckOperationFilter.cs View File

@ -0,0 +1,32 @@
using Microsoft.AspNetCore.Authorization;
using Swashbuckle.AspNetCore.Swagger;
using Swashbuckle.AspNetCore.SwaggerGen;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Ordering.API.Infrastructure.Filters
{
public class AuthorizeCheckOperationFilter : IOperationFilter
{
public void Apply(Operation operation, OperationFilterContext context)
{
// Check for authorize attribute
var hasAuthorize = context.ApiDescription.ControllerAttributes().OfType<AuthorizeAttribute>().Any() ||
context.ApiDescription.ActionAttributes().OfType<AuthorizeAttribute>().Any();
if (hasAuthorize)
{
operation.Responses.Add("401", new Response { Description = "Unauthorized" });
operation.Responses.Add("403", new Response { Description = "Forbidden" });
operation.Security = new List<IDictionary<string, IEnumerable<string>>>();
operation.Security.Add(new Dictionary<string, IEnumerable<string>>
{
{ "oauth2", new [] { "orderingapi" } }
});
}
}
}
}

+ 18
- 0
src/Services/Ordering/Ordering.API/Startup.cs View File

@ -5,6 +5,7 @@
using Autofac.Extensions.DependencyInjection;
using global::Ordering.API.Application.IntegrationEvents;
using global::Ordering.API.Application.IntegrationEvents.Events;
using global::Ordering.API.Infrastructure.Filters;
using Infrastructure;
using Infrastructure.AutofacModules;
using Infrastructure.Filters;
@ -26,7 +27,9 @@
using Ordering.Infrastructure;
using Polly;
using RabbitMQ.Client;
using Swashbuckle.AspNetCore.Swagger;
using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Data.SqlClient;
using System.Reflection;
@ -98,6 +101,20 @@
Description = "The Ordering Service HTTP API",
TermsOfService = "Terms Of Service"
});
options.AddSecurityDefinition("oauth2", new OAuth2Scheme
{
Type = "oauth2",
Flow = "implicit",
AuthorizationUrl = $"{Configuration.GetValue<string>("IdentityUrlExternal")}/connect/authorize",
TokenUrl = $"{Configuration.GetValue<string>("IdentityUrlExternal")}/connect/token",
Scopes = new Dictionary<string, string>()
{
{ "orders", "Ordering API" }
}
});
options.OperationFilter<AuthorizeCheckOperationFilter>();
});
services.AddCors(options =>
@ -174,6 +191,7 @@
.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
c.ConfigureOAuth2("orderingswaggerui", "", "", "Ordering Swagger UI");
});
WaitForSqlAvailabilityAsync(loggerFactory, app, env).Wait();


+ 1
- 1
src/Services/Payment/Payment.API/Controllers/HomeController.cs View File

@ -13,7 +13,7 @@ namespace Payment.API.Controllers
// GET: /<controller>/
public IActionResult Index()
{
return new RedirectResult("~/swagger/ui");
return new RedirectResult("~/swagger");
}
}
}

+ 1
- 1
src/Services/Payment/Payment.API/Dockerfile View File

@ -1,4 +1,4 @@
FROM microsoft/aspnetcore:1.1
FROM microsoft/aspnetcore:1.1.2
ARG source
WORKDIR /app
EXPOSE 80


Loading…
Cancel
Save