我正在使用Swashbuckle (5.3.2),它会生成一个漂亮的API文档。
为了澄清我的问题,我建立了一个没有实际意义的小例子项目。
API只能使用有效的API密钥。 为此,我引入了一个ApiKeyFilter来验证api_key并读取相应的角色。 ApiKeyFilter
控制器/资源只能被拥有相应角色的请求者访问。 PetController
到目前为止一切都很好,没有问题。 问题: 现在我希望在API生成过程中考虑“用户”角色。我只想在文档中显示用户可以使用此api_key消费的资源和操作。 输出应该类似于(/swagger/ui/index?api_key=XXX):
Admin_api_key:
我已经查看了 DelegatingHandler,但在任何 Swashbuckle 过滤器(OperationFilter、DocumentFilter)中都无法读取 Principal,并且我也无法在 CustomProvider 中读取 Principal。
I found some similar question/issues but no real answer. 使用swagger编写Web API文档 使用Swashbuckle和ASP.NET Identity限制访问某些API控制器的Swagger {hxxps://}github.com/domaindrivendev/Swashbuckle/issues/334 {hxxps://}github.com/domaindrivendev/Swashbuckle/issues/735 {hxxps://}github.com/domaindrivendev/Swashbuckle/issues/478
为了澄清我的问题,我建立了一个没有实际意义的小例子项目。
API只能使用有效的API密钥。 为此,我引入了一个ApiKeyFilter来验证api_key并读取相应的角色。 ApiKeyFilter
public class ApiKeyFilter : IAuthenticationFilter
{
private static Dictionary<string, String[]> allowedApps = new Dictionary<string, String[]>();
private readonly string authenticationScheme = "Bearer";
private readonly string queryStringApiKey = "api_key";
public bool AllowMultiple
{
get { return false; }
}
public ApiKeyFilter()
{
if (allowedApps.Count == 0)
{
allowedApps.Add("PetLover_api_key", new []{"PetLover"});
allowedApps.Add("CarOwner_api_key", new []{"CarOwner"});
allowedApps.Add("Admin_api_key", new []{"PetLover","CarOwner"});
}
}
public Task AuthenticateAsync(HttpAuthenticationContext context, CancellationToken cancellationToken)
{
var req = context.Request;
Dictionary<string, string> queryStrings = req.GetQueryNameValuePairs().ToDictionary(x => x.Key.ToLower(), x => x.Value);
string rawAuthzHeader = null;
if (queryStrings.ContainsKey(queryStringApiKey))
{
rawAuthzHeader = queryStrings[queryStringApiKey];
}
else if (req.Headers.Authorization != null && authenticationScheme.Equals(req.Headers.Authorization.Scheme, StringComparison.OrdinalIgnoreCase))
{
rawAuthzHeader = req.Headers.Authorization.Parameter;
}
if (rawAuthzHeader != null && allowedApps.ContainsKey(rawAuthzHeader))
{
var currentPrincipal = new GenericPrincipal(new GenericIdentity(rawAuthzHeader), allowedApps[rawAuthzHeader]);
context.Principal = currentPrincipal;
}
else
{
context.ErrorResult = new UnauthorizedResult(new AuthenticationHeaderValue[0], context.Request);
}
return Task.FromResult(0);
}
public Task ChallengeAsync(HttpAuthenticationChallengeContext context, CancellationToken cancellationToken)
{
context.Result = new ResultWithChallenge(context.Result);
return Task.FromResult(0);
}
}
public class ResultWithChallenge : IHttpActionResult
{
private readonly string authenticationScheme = "amx";
private readonly IHttpActionResult next;
public ResultWithChallenge(IHttpActionResult next)
{
this.next = next;
}
public async Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
var response = await next.ExecuteAsync(cancellationToken);
if (response.StatusCode == HttpStatusCode.Unauthorized)
{
response.Headers.WwwAuthenticate.Add(new AuthenticationHeaderValue(authenticationScheme));
}
return response;
}
}
控制器/资源只能被拥有相应角色的请求者访问。 PetController
[Authorize(Roles = "PetLover")]
[RoutePrefix("api/pets")]
public class PetController : ApiController
{
// GET api/pet
[Route]
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
// GET api/pet/5
[Route("{id:int}")]
public string Get(int id)
{
return "value";
}
// POST api/pet
[Route]
public void Post([FromBody]string value)
{
}
// PUT api/pet/5
public void Put(int id, [FromBody]string value)
{
}
// DELETE api/pet/5
public void Delete(int id)
{
}
}
汽车控制器
[RoutePrefix("api/cars")]
public class CarController : ApiController
{
// GET api/car
[AllowAnonymous]
[Route]
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
// GET api/car/5
[Authorize(Roles = "CarOwner")]
[Route("{id:int}")]
public string Get(int id)
{
return "value";
}
// POST api/car
[Authorize(Roles = "CarOwner")]
[Route]
public void Post([FromBody]string value)
{
}
}
WebApiConfig
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.MapHttpAttributeRoutes();
config.Filters.Add(new ApiKeyFilter());
//config.MessageHandlers.Add(new CustomAuthenticationMessageHandler());
}
}
到目前为止一切都很好,没有问题。 问题: 现在我希望在API生成过程中考虑“用户”角色。我只想在文档中显示用户可以使用此api_key消费的资源和操作。 输出应该类似于(/swagger/ui/index?api_key=XXX):
Admin_api_key:
- 汽车
- 获取 /api/cars
- 发布 /api/cars
- 获取 /api/cars/{id}
- 宠物
- 获取 /api/pets
- 发布 /api/pets
- 获取 /api/pets/{id}
- 汽车
- 获取 /api/cars
- 发布 /api/cars
- 获取 /api/cars/{id}
- 汽车
- 获取 /api/cars
- 宠物
- 获取 /api/pets
- 发布 /api/pets
- 获取 /api/pets/{id}
- 无内容显示
我已经查看了 DelegatingHandler,但在任何 Swashbuckle 过滤器(OperationFilter、DocumentFilter)中都无法读取 Principal,并且我也无法在 CustomProvider 中读取 Principal。
public class CustomAuthenticationMessageHandler : DelegatingHandler
{
private static Dictionary<string, String[]> allowedApps = new Dictionary<string, String[]>();
private readonly string authenticationScheme = "Bearer";
private readonly string queryStringApiKey = "api_key";
public bool AllowMultiple
{
get { return false; }
}
public CustomAuthenticationMessageHandler()
{
if (allowedApps.Count == 0)
{
allowedApps.Add("PetLover_api_key", new[] {"PetLover"});
allowedApps.Add("CarOwner_api_key", new[] {"CarOwner"});
allowedApps.Add("Admin_api_key", new[] {"PetLover", "CarOwner"});
}
}
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var req = request;
Dictionary<string, string> queryStrings = req.GetQueryNameValuePairs().ToDictionary(x => x.Key.ToLower(), x => x.Value);
string rawAuthzHeader = null;
if (queryStrings.ContainsKey(queryStringApiKey))
{
rawAuthzHeader = queryStrings[queryStringApiKey];
}
else if (req.Headers.Authorization != null && authenticationScheme.Equals(req.Headers.Authorization.Scheme, StringComparison.OrdinalIgnoreCase))
{
rawAuthzHeader = req.Headers.Authorization.Parameter;
}
if (rawAuthzHeader != null && allowedApps.ContainsKey(rawAuthzHeader))
{
var currentPrincipal = new GenericPrincipal(new GenericIdentity(rawAuthzHeader), allowedApps[rawAuthzHeader]);
request.GetRequestContext().Principal = currentPrincipal;
}
else
{
}
return await base.SendAsync(request, cancellationToken);
}
}
I found some similar question/issues but no real answer. 使用swagger编写Web API文档 使用Swashbuckle和ASP.NET Identity限制访问某些API控制器的Swagger {hxxps://}github.com/domaindrivendev/Swashbuckle/issues/334 {hxxps://}github.com/domaindrivendev/Swashbuckle/issues/735 {hxxps://}github.com/domaindrivendev/Swashbuckle/issues/478