J'ai documenté mon api en utilisant Swashbuckle.AspNetCore.Swagger et je souhaite tester certaines ressources dotées de l'attribut Autoriser en utilisant swagger ui.
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System.Linq;
namespace Api.Controllers
{
[Route("[controller]")]
[Authorize]
public class IdentityController : ControllerBase
{
[HttpGet]
public IActionResult Get()
{
return new JsonResult(from c in User.Claims select new { c.Type, c.Value });
}
}
}
Le code de réponse est Unauthorized 401, alors comment puis-je l'autoriser en utilisant swagger?
J'ai une configuration de serveur d'autorisation utilisant IdentityServer4.
services.AddIdentityServer()
.AddTemporarySigningCredential()
.AddInMemoryPersistedGrants()
.AddInMemoryIdentityResources(Config.GetIdentityResources())
.AddInMemoryApiResources(Config.GetApiResources())
.AddInMemoryClients(Config.GetClients())
.AddAspNetIdentity<ApplicationUser>();
public class Config
{
// scopes define the resources in your system
public static IEnumerable<IdentityResource> GetIdentityResources()
{
return new List<IdentityResource>
{
new IdentityResources.OpenId(),
new IdentityResources.Profile(),
};
}
public static IEnumerable<ApiResource> GetApiResources()
{
return new List<ApiResource>
{
new ApiResource("api1", "My API")
};
}
...
...
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory,
ECommerceDbContext context)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
app.UseIdentityServerAuthentication(new IdentityServerAuthenticationOptions
{
Authority = "http://localhost:5000/",
RequireHttpsMetadata = false,
AutomaticAuthenticate = true,
ApiName = "api1"
});
// Enable middleware to serve generated Swagger as a JSON endpoint.
app.UseSwagger();
// Enable middleware to serve swagger-ui (HTML, JS, CSS etc.), specifying the Swagger JSON endpoint.
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
});
DbInitialiser.Init(context);
app.UseMvc();
}
Je souhaite un bouton d'autorisation qui redirige vers un écran de connexion, puis accorde l'accès aux ressources de l'API pour lesquelles l'utilisateur dispose d'autorisations. Est-il possible d'utiliser le middleware asp.net core 1.1 Swagger Core pour ce faire? Ou dois-je écrire du javascript qui obtient un jeton du serveur d'autorisations IdentityServer4? S'il vous plaît, aidez-moi car je suis nouveau en authentification et autorisation
J'ai résolu ce problème en ajoutant un nouveau client au projet IdentityServer4 Authorization Server.
// clients want to access resources (aka scopes)
public static IEnumerable<Client> GetClients()
{
// client credentials client
return new List<Client>
{
new Client
{
ClientId="swaggerui",
ClientName = "Swagger UI",
AllowedGrantTypes=GrantTypes.Implicit,
AllowAccessTokensViaBrowser=true,
RedirectUris = { "http://localhost:49831/swagger/o2c.html" },
PostLogoutRedirectUris={ "http://localhost:49831/swagger/" },
AllowedScopes = {"api1"}
},
...
...
...
}
}
J'ai créé un swagger OperationFilter dans cette API afin qu'une icône en forme de point d'exclamation rouge apparaisse à côté de la méthode nécessitant une autorisation.
internal 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 [] { "api1" } }
});
}
}
}
Pour finir, j'ai configuré l'autorisation dans swagger en ajoutant une définition de sécurité et un filtre de contrôle oauth2
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new Info
{
Version = "v1",
Title = "ECommerce API",
Description = "",
TermsOfService = "None",
Contact = new Contact { Name = "", Email = "", Url = "" },
License = new License { Name = "", Url = "" }
});
//Set the comments path for the swagger json and ui.
var basePath = PlatformServices.Default.Application.ApplicationBasePath;
var xmlPath = Path.Combine(basePath, "WebApi.xml");
c.IncludeXmlComments(xmlPath);
c.OperationFilter<AuthorizeCheckOperationFilter>();
c.AddSecurityDefinition("oauth2", new OAuth2Scheme
{
Type = "oauth2",
Flow = "implicit",
AuthorizationUrl = "http://localhost:5000/connect/authorize",
TokenUrl = "http://localhost:5000/connect/token",
Scopes = new Dictionary<string, string>()
{
{ "api1", "My API" }
}
});
});
Comme mentionné par James dans le commentaire de la réponse acceptée, la manière de vérifier l'attribut Autoriser est légèrement différente maintenant, la variable AuthorizeCheckOperationFilter
dans la réponse doit être légèrement modifiée, cela peut ne pas être à 100% la meilleure façon de le faire, mais je n'ai pas encore eu des problèmes avec le code ci-dessous.
internal class AuthorizeCheckOperationFilter : IOperationFilter
{
public void Apply(Operation operation, OperationFilterContext context)
{
context.ApiDescription.TryGetMethodInfo(out var methodInfo);
if (methodInfo == null)
return;
var hasAuthorizeAttribute = false;
if (methodInfo.MemberType == MemberTypes.Method)
{
// NOTE: Check the controller itself has Authorize attribute
hasAuthorizeAttribute = methodInfo.DeclaringType.GetCustomAttributes(true).OfType<AuthorizeAttribute>().Any();
// NOTE: Controller has Authorize attribute, so check the endpoint itself.
// Take into account the allow anonymous attribute
if (hasAuthorizeAttribute)
hasAuthorizeAttribute = !methodInfo.GetCustomAttributes(true).OfType<AllowAnonymousAttribute>().Any();
else
hasAuthorizeAttribute = methodInfo.GetCustomAttributes(true).OfType<AuthorizeAttribute>().Any();
}
if (!hasAuthorizeAttribute)
return;
operation.Responses.Add(StatusCodes.Status401Unauthorized.ToString(), new Response { Description = "Unauthorized" });
operation.Responses.Add(StatusCodes.Status403Forbidden.ToString(), new Response { Description = "Forbidden" });
// NOTE: This adds the "Padlock" icon to the endpoint in swagger,
// we can also pass through the names of the policies in the string[]
// which will indicate which permission you require.
operation.Security = new List<IDictionary<string, IEnumerable<string>>>();
operation.Security.Add(new Dictionary<string, IEnumerable<string>>
{
{ "Bearer", new string[] { } }
});
}
}