Swashbuckle.AspNetCore.Swaggerを使用してAPIを文書化しました。swaggeruiを使用して、Authorize属性を持つリソースをテストします。
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 });
}
}
}
応答コードは無許可401ですが、swaggerを使用してこれをどのように認証できますか?
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();
}
ログイン画面にリダイレクトし、ユーザーが権限を持つAPIリソースへのアクセスを許可する承認ボタンが必要です。これを行うためにasp.net core 1.1 Swaggerミドルウェアを使用することは可能ですか?または、IdentityServer4承認サーバーからトークンを取得するjavascriptを記述する必要がありますか?私は認証と承認に不慣れなので、助けてください
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"}
},
...
...
...
}
}
承認が必要なメソッドの横に赤い感嘆符アイコンが表示されるように、APIでSwagger OperationFilterを作成しました
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" } }
});
}
}
}
完了するには、oauth2セキュリティ定義とoperationfilterを追加してswaggerで承認を構成しました
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" }
}
});
});
承認された回答へのコメントでジェームズが述べたように、Authorize属性を確認する方法は少し異なります。回答のAuthorizeCheckOperationFilter
を少し調整する必要があります。これは、これを行うための100%の最善の方法ではないかもしれません。ただし、以下のコードには問題がありませんでした。
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[] { } }
});
}
}