4
4
using FluentValidation . AspNetCore ;
5
5
using MicroElements . Swashbuckle . FluentValidation ;
6
6
using Microsoft . AspNetCore . Authentication . JwtBearer ;
7
+ using Microsoft . AspNetCore . Authorization ;
7
8
using Microsoft . AspNetCore . Builder ;
8
9
using Microsoft . AspNetCore . Hosting ;
9
10
using Microsoft . AspNetCore . Mvc ;
11
+ using Microsoft . AspNetCore . Mvc . Authorization ;
10
12
using Microsoft . AspNetCore . ResponseCompression ;
11
13
using Microsoft . Extensions . Configuration ;
12
14
using Microsoft . Extensions . DependencyInjection ;
13
15
using Microsoft . Extensions . Hosting ;
14
16
using Microsoft . OpenApi . Models ;
15
17
using Swashbuckle . AspNetCore . Swagger ;
18
+ using System . Collections . Generic ;
16
19
using System . Linq ;
17
20
18
21
namespace AdminAssistant . Blazor . Server
@@ -58,9 +61,14 @@ public void ConfigureServices(IServiceCollection services)
58
61
services . AddResponseCompression ( opts => opts . MimeTypes = ResponseCompressionDefaults . MimeTypes . Concat ( new [ ] { "application/octet-stream" } ) ) ;
59
62
60
63
services . AddHttpContextAccessor ( ) ;
61
- services . AddControllers ( )
62
- . AddNewtonsoftJson ( )
63
- . AddFluentValidation ( c => c . RegisterValidatorsFromAssemblyContaining < Infra . DAL . IDatabasePersistable > ( ) ) ;
64
+ services . AddControllers ( opts =>
65
+ {
66
+ // Add [Authorize] for all controllers ...
67
+ var policy = new AuthorizationPolicyBuilder ( ) . RequireAuthenticatedUser ( ) . Build ( ) ;
68
+ opts . Filters . Add ( new AuthorizeFilter ( policy ) ) ;
69
+
70
+ } ) . AddNewtonsoftJson ( )
71
+ . AddFluentValidation ( c => c . RegisterValidatorsFromAssemblyContaining < Infra . DAL . IDatabasePersistable > ( ) ) ;
64
72
65
73
services . AddSwaggerGen ( c =>
66
74
{
@@ -77,10 +85,31 @@ public void ConfigureServices(IServiceCollection services)
77
85
} ) ;
78
86
79
87
c . SwaggerDoc ( WebAPIVersion , new OpenApiInfo { Title = WebAPITitle , Version = WebAPIVersion } ) ; // Add OpenAPI/Swagger middleware
88
+ c . AddSecurityDefinition ( "Bearer" , new OpenApiSecurityScheme
89
+ {
90
+ Name = "Authorization" ,
91
+ In = ParameterLocation . Header ,
92
+ Type = SecuritySchemeType . OAuth2 ,
93
+ Flows = new OpenApiOAuthFlows
94
+ {
95
+ Implicit = new OpenApiOAuthFlow
96
+ {
97
+ Scopes = new Dictionary < string , string >
98
+ {
99
+ { "openid" , "Open Id" }
100
+ } ,
101
+ AuthorizationUrl = new System . Uri ( $ "https://{ configSettings . Auth0Authority } /" + "authorize?audience=" + configSettings . Auth0ApiIdentifier )
102
+ }
103
+ }
104
+ } ) ;
80
105
c . AddFluentValidationRules ( ) ; // Adds fluent validation rules to swagger schema See: https://github.com/micro-elements/MicroElements.Swashbuckle.FluentValidation
81
106
82
107
// Include documentation from Annotations (Swashbuckle.AspNetCore.Annotations)...
83
108
c . EnableAnnotations ( ) ; // https://github.com/domaindrivendev/Swashbuckle.AspNetCore#install-and-enable-annotations
109
+
110
+ // Let Swagger UI know that we put Authorize on all endpoints using a filter policy
111
+ // See services.AddControllers code above ...
112
+ c . OperationFilter < SwaggerSecurityRequirementsOperationFilter > ( ) ;
84
113
} ) ;
85
114
services . AddSwaggerGenNewtonsoftSupport ( ) ;
86
115
@@ -113,6 +142,7 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
113
142
c . SwaggerEndpoint ( "/swagger/v1/swagger.json" , WebAPITitle ) ;
114
143
c . RoutePrefix = "api-docs" ;
115
144
c . DocExpansion ( Swashbuckle . AspNetCore . SwaggerUI . DocExpansion . List ) ;
145
+ c . OAuthClientId ( _configuration . GetSection ( nameof ( ConfigurationSettings ) ) . Get < ConfigurationSettings > ( ) . Auth0ClientId ) ;
116
146
} ) ;
117
147
118
148
app . UseHttpsRedirection ( ) ;
@@ -129,4 +159,51 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
129
159
} ) ;
130
160
}
131
161
}
162
+
163
+ public class SwaggerSecurityRequirementsOperationFilter : Swashbuckle . AspNetCore . SwaggerGen . IOperationFilter
164
+ {
165
+ /// <summary>
166
+ /// Applies this filter on swagger documentation generation.
167
+ /// </summary>
168
+ /// <param name="operation"></param>
169
+ /// <param name="context"></param>
170
+ public void Apply ( OpenApiOperation operation , Swashbuckle . AspNetCore . SwaggerGen . OperationFilterContext context )
171
+ {
172
+ // then check if there is a method-level 'AllowAnonymous', as this overrides any controller-level 'Authorize'
173
+ var anonControllerScope = context
174
+ . MethodInfo
175
+ . DeclaringType
176
+ . GetCustomAttributes ( true )
177
+ . OfType < AllowAnonymousAttribute > ( ) ;
178
+
179
+ var anonMethodScope = context
180
+ . MethodInfo
181
+ . GetCustomAttributes ( true )
182
+ . OfType < AllowAnonymousAttribute > ( ) ;
183
+
184
+ // only add authorization specification information if there is at least one 'Authorize' in the chain and NO method-level 'AllowAnonymous'
185
+ if ( ! anonMethodScope . Any ( ) && ! anonControllerScope . Any ( ) )
186
+ {
187
+ // add generic message if the controller methods dont already specify the response type
188
+ if ( ! operation . Responses . ContainsKey ( "401" ) )
189
+ operation . Responses . Add ( "401" , new OpenApiResponse { Description = "If Authorization header not present, has no value or no valid jwt bearer token" } ) ;
190
+
191
+ if ( ! operation . Responses . ContainsKey ( "403" ) )
192
+ operation . Responses . Add ( "403" , new OpenApiResponse { Description = "If user not authorized to perform requested action" } ) ;
193
+
194
+ var jwtAuthScheme = new OpenApiSecurityScheme
195
+ {
196
+ Reference = new OpenApiReference { Type = ReferenceType . SecurityScheme , Id = "Bearer" }
197
+ } ;
198
+
199
+ operation . Security = new List < OpenApiSecurityRequirement >
200
+ {
201
+ new OpenApiSecurityRequirement
202
+ {
203
+ [ jwtAuthScheme ] = new List < string > ( )
204
+ }
205
+ } ;
206
+ }
207
+ }
208
+ }
132
209
}
0 commit comments