diff --git a/framework/src/Volo.Abp.Swashbuckle/Microsoft/AspNetCore/Builder/AbpSwaggerUIBuilderExtensions.cs b/framework/src/Volo.Abp.Swashbuckle/Microsoft/AspNetCore/Builder/AbpSwaggerUIBuilderExtensions.cs index 4ea501626b..4a54191459 100644 --- a/framework/src/Volo.Abp.Swashbuckle/Microsoft/AspNetCore/Builder/AbpSwaggerUIBuilderExtensions.cs +++ b/framework/src/Volo.Abp.Swashbuckle/Microsoft/AspNetCore/Builder/AbpSwaggerUIBuilderExtensions.cs @@ -1,7 +1,6 @@ using System; using Microsoft.Extensions.DependencyInjection; using Swashbuckle.AspNetCore.SwaggerUI; -using Volo.Abp; using Volo.Abp.Swashbuckle; namespace Microsoft.AspNetCore.Builder diff --git a/framework/src/Volo.Abp.Swashbuckle/Microsoft/Extensions/DependencyInjection/AbpSwaggerGenServiceCollectionExtensions.cs b/framework/src/Volo.Abp.Swashbuckle/Microsoft/Extensions/DependencyInjection/AbpSwaggerGenServiceCollectionExtensions.cs new file mode 100644 index 0000000000..1da6958830 --- /dev/null +++ b/framework/src/Volo.Abp.Swashbuckle/Microsoft/Extensions/DependencyInjection/AbpSwaggerGenServiceCollectionExtensions.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using JetBrains.Annotations; +using Microsoft.OpenApi.Models; +using Swashbuckle.AspNetCore.SwaggerGen; + +namespace Microsoft.Extensions.DependencyInjection +{ + public static class AbpSwaggerGenServiceCollectionExtensions + { + public static IServiceCollection AddAbpSwaggerGenWithOAuth( + this IServiceCollection services, + [NotNull] string authority, + [NotNull] Dictionary scopes, + Action setupAction = null) + { + return services.AddSwaggerGen( + options => + { + options.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme + { + Type = SecuritySchemeType.OAuth2, + Flows = new OpenApiOAuthFlows + { + AuthorizationCode = new OpenApiOAuthFlow + { + AuthorizationUrl = new Uri($"{authority.EnsureEndsWith('/')}connect/authorize"), + Scopes = scopes, + TokenUrl = new Uri($"{authority.EnsureEndsWith('/')}connect/token") + } + } + }); + + options.AddSecurityRequirement(new OpenApiSecurityRequirement + { + { + new OpenApiSecurityScheme + { + Reference = new OpenApiReference + { + Type = ReferenceType.SecurityScheme, + Id = "oauth2" + } + }, + Array.Empty() + } + }); + + + setupAction?.Invoke(options); + }); + } + } +} diff --git a/framework/src/Volo.Abp.Swashbuckle/wwwroot/swagger/ui/abp.swagger.js b/framework/src/Volo.Abp.Swashbuckle/wwwroot/swagger/ui/abp.swagger.js index b1b9614640..22277cb194 100644 --- a/framework/src/Volo.Abp.Swashbuckle/wwwroot/swagger/ui/abp.swagger.js +++ b/framework/src/Volo.Abp.Swashbuckle/wwwroot/swagger/ui/abp.swagger.js @@ -3,8 +3,7 @@ (function () { abp.SwaggerUIBundle = function (configObject) { configObject.requestInterceptor = function (request) { - var token = abp.auth.getToken(); - request.headers.Authorization = token ? "Bearer " + token : null; + var antiForgeryToken = abp.security.antiForgery.getToken(); if (antiForgeryToken) { request.headers[abp.security.antiForgery.tokenHeaderName] = antiForgeryToken; diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.DbMigrator/appsettings.json b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.DbMigrator/appsettings.json index 0accabeaaa..2e4a69bd49 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.DbMigrator/appsettings.json +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.DbMigrator/appsettings.json @@ -17,6 +17,11 @@ "MyProjectName_Blazor": { "ClientId": "MyProjectName_Blazor", "RootUrl": "https://localhost:44307" + }, + "MyProjectName_Swagger": { + "ClientId": "MyProjectName_Swagger", + "ClientSecret": "1q2w3e*", + "RootUrl": "https://localhost:44300" } } } diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Domain/IdentityServer/IdentityServerDataSeedContributor.cs b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Domain/IdentityServer/IdentityServerDataSeedContributor.cs index ebb027fa86..7397d2238f 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Domain/IdentityServer/IdentityServerDataSeedContributor.cs +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Domain/IdentityServer/IdentityServerDataSeedContributor.cs @@ -188,6 +188,22 @@ namespace MyCompanyName.MyProjectName.IdentityServer postLogoutRedirectUri: $"{blazorRootUrl}/authentication/logout-callback" ); } + + // Swagger Client + var swaggerClientId = configurationSection["MyProjectName_Swagger:ClientId"]; + if (!swaggerClientId.IsNullOrWhiteSpace()) + { + var swaggerRootUrl = configurationSection["MyProjectName_Swagger:RootUrl"].TrimEnd('/'); + + await CreateClientAsync( + name: swaggerClientId, + scopes: commonScopes, + grantTypes: new[] { "authorization_code" }, + secret: configurationSection["MyProjectName_Swagger:ClientSecret"]?.Sha256(), + requireClientSecret: false, + redirectUri: $"{swaggerRootUrl}/swagger/oauth2-redirect.html" + ); + } } private async Task CreateClientAsync( @@ -281,4 +297,4 @@ namespace MyCompanyName.MyProjectName.IdentityServer return await _clientRepository.UpdateAsync(client); } } -} \ No newline at end of file +} diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.Host/MyCompanyName.MyProjectName.HttpApi.Host.csproj b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.Host/MyCompanyName.MyProjectName.HttpApi.Host.csproj index 26f3d6148a..00fcebd687 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.Host/MyCompanyName.MyProjectName.HttpApi.Host.csproj +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.Host/MyCompanyName.MyProjectName.HttpApi.Host.csproj @@ -12,7 +12,6 @@ - @@ -20,6 +19,7 @@ + diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.Host/MyProjectNameHttpApiHostModule.cs b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.Host/MyProjectNameHttpApiHostModule.cs index 1a6c410619..6a0ee29447 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.Host/MyProjectNameHttpApiHostModule.cs +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.Host/MyProjectNameHttpApiHostModule.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.IO; using System.Linq; using Microsoft.AspNetCore.Authentication.JwtBearer; @@ -23,6 +24,7 @@ using Volo.Abp.Caching; using Volo.Abp.Caching.StackExchangeRedis; using Volo.Abp.Localization; using Volo.Abp.Modularity; +using Volo.Abp.Swashbuckle; using Volo.Abp.VirtualFileSystem; namespace MyCompanyName.MyProjectName @@ -34,7 +36,8 @@ namespace MyCompanyName.MyProjectName typeof(AbpAspNetCoreMvcUiMultiTenancyModule), typeof(MyProjectNameApplicationModule), typeof(MyProjectNameEntityFrameworkCoreDbMigrationsModule), - typeof(AbpAspNetCoreSerilogModule) + typeof(AbpAspNetCoreSerilogModule), + typeof(AbpSwashbuckleModule) )] public class MyProjectNameHttpApiHostModule : AbpModule { @@ -52,7 +55,7 @@ namespace MyCompanyName.MyProjectName ConfigureVirtualFileSystem(context); ConfigureRedis(context, configuration, hostingEnvironment); ConfigureCors(context, configuration); - ConfigureSwaggerServices(context); + ConfigureSwaggerServices(context, configuration); } private void ConfigureCache(IConfiguration configuration) @@ -103,9 +106,14 @@ namespace MyCompanyName.MyProjectName }); } - private static void ConfigureSwaggerServices(ServiceConfigurationContext context) + private static void ConfigureSwaggerServices(ServiceConfigurationContext context, IConfiguration configuration) { - context.Services.AddSwaggerGen( + context.Services.AddAbpSwaggerGenWithOAuth( + configuration["AuthServer:Authority"], + new Dictionary + { + {"MyProjectName", "MyProjectName API"} + }, options => { options.SwaggerDoc("v1", new OpenApiInfo {Title = "MyProjectName API", Version = "v1"}); @@ -198,11 +206,18 @@ namespace MyCompanyName.MyProjectName app.UseAuthorization(); app.UseSwagger(); - app.UseSwaggerUI(options => { options.SwaggerEndpoint("/swagger/v1/swagger.json", "MyProjectName API"); }); + app.UseSwaggerUI(options => + { + options.SwaggerEndpoint("/swagger/v1/swagger.json", "MyProjectName API"); + + var configuration = context.GetConfiguration(); + options.OAuthClientId(configuration["AuthServer:SwaggerClientId"]); + options.OAuthClientSecret(configuration["AuthServer:SwaggerClientSecret"]); + }); app.UseAuditing(); app.UseAbpSerilogEnrichers(); app.UseConfiguredEndpoints(); } } -} \ No newline at end of file +} diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.Host/appsettings.json b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.Host/appsettings.json index ab4349b9c6..6c64a7b397 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.Host/appsettings.json +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.Host/appsettings.json @@ -10,8 +10,10 @@ }, "AuthServer": { "Authority": "https://localhost:44301", - "RequireHttpsMetadata": "true" - }, + "RequireHttpsMetadata": "true", + "SwaggerClientId": "MyProjectName_Swagger", + "SwaggerClientSecret": "1q2w3e*" +}, "StringEncryption": { "DefaultPassPhrase": "gsKnGZ041HLL4IM8" }, diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.HostWithIds/MyCompanyName.MyProjectName.HttpApi.HostWithIds.csproj b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.HostWithIds/MyCompanyName.MyProjectName.HttpApi.HostWithIds.csproj index d4cb35b5b0..f9de557950 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.HostWithIds/MyCompanyName.MyProjectName.HttpApi.HostWithIds.csproj +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.HostWithIds/MyCompanyName.MyProjectName.HttpApi.HostWithIds.csproj @@ -19,6 +19,7 @@ + diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.HostWithIds/MyProjectNameHttpApiHostModule.cs b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.HostWithIds/MyProjectNameHttpApiHostModule.cs index 9f1b0c8168..231544bdbc 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.HostWithIds/MyProjectNameHttpApiHostModule.cs +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.HostWithIds/MyProjectNameHttpApiHostModule.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.IO; using System.Linq; using System.Net.Http; @@ -23,6 +24,7 @@ using Volo.Abp.AspNetCore.Serilog; using Volo.Abp.Autofac; using Volo.Abp.Localization; using Volo.Abp.Modularity; +using Volo.Abp.Swashbuckle; using Volo.Abp.UI.Navigation.Urls; using Volo.Abp.VirtualFileSystem; @@ -37,7 +39,8 @@ namespace MyCompanyName.MyProjectName typeof(AbpAspNetCoreMvcUiBasicThemeModule), typeof(AbpAspNetCoreAuthenticationJwtBearerModule), typeof(AbpAccountWebIdentityServerModule), - typeof(AbpAspNetCoreSerilogModule) + typeof(AbpAspNetCoreSerilogModule), + typeof(AbpSwashbuckleModule) )] public class MyProjectNameHttpApiHostModule : AbpModule { @@ -64,10 +67,7 @@ namespace MyCompanyName.MyProjectName { options.StyleBundles.Configure( BasicThemeBundles.Styles.Global, - bundle => - { - bundle.AddFiles("/global-styles.css"); - } + bundle => { bundle.AddFiles("/global-styles.css"); } ); }); } @@ -211,7 +211,10 @@ namespace MyCompanyName.MyProjectName app.UseAuthorization(); app.UseSwagger(); - app.UseSwaggerUI(options => { options.SwaggerEndpoint("/swagger/v1/swagger.json", "MyProjectName API"); }); + app.UseAbpSwaggerUI(c => + { + c.SwaggerEndpoint("/swagger/v1/swagger.json", "MyProjectName API"); + }); app.UseAuditing(); app.UseAbpSerilogEnrichers(); diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.IdentityServer/appsettings.json b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.IdentityServer/appsettings.json index b2fa57365a..e9152eb6ad 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.IdentityServer/appsettings.json +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.IdentityServer/appsettings.json @@ -1,7 +1,7 @@ { "App": { "SelfUrl": "https://localhost:44301", - "CorsOrigins": "https://*.MyProjectName.com,http://localhost:4200,https://localhost:44307" + "CorsOrigins": "https://*.MyProjectName.com,http://localhost:4200,https://localhost:44307,https://localhost:44300" }, "ConnectionStrings": { "Default": "Server=(LocalDb)\\MSSQLLocalDB;Database=MyProjectName;Trusted_Connection=True;MultipleActiveResultSets=true" diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.HttpApi.Host/MyCompanyName.MyProjectName.HttpApi.Host.csproj b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.HttpApi.Host/MyCompanyName.MyProjectName.HttpApi.Host.csproj index 2d29e55d81..a09f201dfa 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.HttpApi.Host/MyCompanyName.MyProjectName.HttpApi.Host.csproj +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.HttpApi.Host/MyCompanyName.MyProjectName.HttpApi.Host.csproj @@ -12,7 +12,6 @@ - @@ -22,6 +21,7 @@ + diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.HttpApi.Host/MyProjectNameHttpApiHostModule.cs b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.HttpApi.Host/MyProjectNameHttpApiHostModule.cs index 1c1af02001..abe3a018bd 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.HttpApi.Host/MyProjectNameHttpApiHostModule.cs +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.HttpApi.Host/MyProjectNameHttpApiHostModule.cs @@ -2,21 +2,19 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; -using System.Security.Claims; using IdentityModel; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Cors; using Microsoft.AspNetCore.DataProtection; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using MyCompanyName.MyProjectName.EntityFrameworkCore; using MyCompanyName.MyProjectName.MultiTenancy; using StackExchange.Redis; using Microsoft.OpenApi.Models; -using Swashbuckle.AspNetCore.Swagger; using Volo.Abp; -using Volo.Abp.AspNetCore.MultiTenancy; using Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy; using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared; using Volo.Abp.AspNetCore.Serilog; @@ -32,6 +30,7 @@ using Volo.Abp.MultiTenancy; using Volo.Abp.PermissionManagement.EntityFrameworkCore; using Volo.Abp.Security.Claims; using Volo.Abp.SettingManagement.EntityFrameworkCore; +using Volo.Abp.Swashbuckle; using Volo.Abp.VirtualFileSystem; namespace MyCompanyName.MyProjectName @@ -47,7 +46,8 @@ namespace MyCompanyName.MyProjectName typeof(AbpAuditLoggingEntityFrameworkCoreModule), typeof(AbpPermissionManagementEntityFrameworkCoreModule), typeof(AbpSettingManagementEntityFrameworkCoreModule), - typeof(AbpAspNetCoreSerilogModule) + typeof(AbpAspNetCoreSerilogModule), + typeof(AbpSwashbuckleModule) )] public class MyProjectNameHttpApiHostModule : AbpModule { @@ -79,10 +79,15 @@ namespace MyCompanyName.MyProjectName }); } - context.Services.AddSwaggerGen( + context.Services.AddAbpSwaggerGenWithOAuth( + configuration["AuthServer:Authority"], + new Dictionary + { + {"MyProjectName", "MyProjectName API"} + }, options => { - options.SwaggerDoc("v1", new OpenApiInfo { Title = "MyProjectName API", Version = "v1" }); + options.SwaggerDoc("v1", new OpenApiInfo {Title = "MyProjectName API", Version = "v1"}); options.DocInclusionPredicate((docName, description) => true); options.CustomSchemaIds(type => type.FullName); }); @@ -179,6 +184,10 @@ namespace MyCompanyName.MyProjectName app.UseSwaggerUI(options => { options.SwaggerEndpoint("/swagger/v1/swagger.json", "Support APP API"); + + var configuration = context.GetConfiguration(); + options.OAuthClientId(configuration["AuthServer:SwaggerClientId"]); + options.OAuthClientSecret(configuration["AuthServer:SwaggerClientSecret"]); }); app.UseAuditing(); app.UseAbpSerilogEnrichers(); diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.HttpApi.Host/appsettings.json b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.HttpApi.Host/appsettings.json index d04f8779b8..d80fc69b59 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.HttpApi.Host/appsettings.json +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.HttpApi.Host/appsettings.json @@ -11,6 +11,8 @@ }, "AuthServer": { "Authority": "https://localhost:44301/", - "RequireHttpsMetadata": "false" + "RequireHttpsMetadata": "false", + "SwaggerClientId": "MyProjectName_Swagger", + "SwaggerClientSecret": "1q2w3e*" } } diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/IdentityServer/IdentityServerDataSeedContributor.cs b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/IdentityServer/IdentityServerDataSeedContributor.cs index f37a50da48..53a1827dba 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/IdentityServer/IdentityServerDataSeedContributor.cs +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/IdentityServer/IdentityServerDataSeedContributor.cs @@ -166,7 +166,7 @@ namespace MyCompanyName.MyProjectName.IdentityServer secret: (configurationSection["MyProjectName_ConsoleTestApp:ClientSecret"] ?? "1q2w3e*").Sha256() ); } - + // Blazor Client var blazorClientId = configurationSection["MyProjectName_Blazor:ClientId"]; if (!blazorClientId.IsNullOrWhiteSpace()) @@ -183,6 +183,22 @@ namespace MyCompanyName.MyProjectName.IdentityServer postLogoutRedirectUri: $"{blazorRootUrl}/authentication/logout-callback" ); } + + // Swagger Client + var swaggerClientId = configurationSection["MyProjectName_Swagger:ClientId"]; + if (!swaggerClientId.IsNullOrWhiteSpace()) + { + var swaggerRootUrl = configurationSection["MyProjectName_Swagger:RootUrl"].TrimEnd('/'); + + await CreateClientAsync( + name: swaggerClientId, + scopes: commonScopes, + grantTypes: new[] { "authorization_code" }, + secret: configurationSection["MyProjectName_Swagger:ClientSecret"]?.Sha256(), + requireClientSecret: false, + redirectUri: $"{swaggerRootUrl}/swagger/oauth2-redirect.html" + ); + } } private async Task CreateClientAsync( diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/appsettings.json b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/appsettings.json index efb325fd37..c3439a2d00 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/appsettings.json +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/appsettings.json @@ -1,7 +1,7 @@ { "App": { "SelfUrl": "https://localhost:44301/", - "CorsOrigins": "https://*.MyProjectName.com,http://localhost:4200,http://localhost:44307,https://localhost:44307" + "CorsOrigins": "https://*.MyProjectName.com,http://localhost:4200,http://localhost:44307,https://localhost:44307,https://localhost:44300" }, "AppSelfUrl": "https://localhost:44301/", "ConnectionStrings": { @@ -27,6 +27,11 @@ }, "MyProjectName_ConsoleTestApp": { "ClientId": "MyProjectName_ConsoleTestApp" + }, + "MyProjectName_Swagger": { + "ClientId": "MyProjectName_Swagger", + "ClientSecret": "1q2w3e*", + "RootUrl": "https://localhost:44300" } } }