我使用的是Swashbuckle(5.3.2),它生成了一个很好的API文档。
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)
{
}
}
CarController
[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());
}
}
carowner_api_key:
在API规范生成期间,我无法访问HttpRequest以读取任何查询字符串或任何头信息。
我已经研究过委托Handler,但在任何Swashbuckle过滤器(OperationFilter,DocumentFilter)中都很难读出主体,而且我也无法在CustomProvider中读出主体。
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);
}
}
我发现了一些类似的问题/问题,但没有真正的答案。
Web API文档使用Swashbuckle和ASP.NET标识限制对swagger中某些API控制器的访问
{hxxps://}github.com/domaindrivendev/Swashbuckle/issues/334
{hxxps://}github.com/domaindrivendev/Swashbuckle/issues/735
{hxxps://}github.com/domaindrivendev/Swashbuckle/issues/478
我现在找到了一个对我有效的解决办法。
我使用CustomAuthenticationMessageHandler(与我的问题相同)将规则放入HttpContext中。
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);
}
}
我引入了一个自定义的Swashbuckle IDocumentFilter,它从HttpContext中读取规则,并从SwaggerDocument中删除该规则不允许的操作和资源(基于api_key)。
public class AuthorizeRoleFilter : IDocumentFilter
{
public void Apply(SwaggerDocument swaggerDoc, SchemaRegistry schemaRegistry, IApiExplorer apiExplorer)
{
IPrincipal user = HttpContext.Current.User;
foreach (ApiDescription apiDescription in apiExplorer.ApiDescriptions)
{
var authorizeAttributes = apiDescription
.ActionDescriptor.GetCustomAttributes<AuthorizeAttribute>().ToList();
authorizeAttributes.AddRange(apiDescription
.ActionDescriptor.ControllerDescriptor.GetCustomAttributes<AuthorizeAttribute>());
if (!authorizeAttributes.Any())
continue;
var roles =
authorizeAttributes
.SelectMany(attr => attr.Roles.Split(','))
.Distinct()
.ToList();
if (!user.Identity.IsAuthenticated || !roles.Any(role => user.IsInRole(role) || role == ""))
{
string key = "/" + apiDescription.RelativePath;
PathItem pathItem = swaggerDoc.paths[key];
switch (apiDescription.HttpMethod.Method.ToLower())
{
case "get":
pathItem.get = null;
break;
case "put":
pathItem.put = null;
break;
case "post":
pathItem.post = null;
break;
case "delete":
pathItem.delete = null;
break;
case "options":
pathItem.options = null;
break;
case "head":
pathItem.head = null;
break;
case "patch":
pathItem.patch = null;
break;
}
if (pathItem.get == null &&
pathItem.put == null &&
pathItem.post == null &&
pathItem.delete == null &&
pathItem.options == null &&
pathItem.head == null &&
pathItem.patch == null)
{
swaggerDoc.paths.Remove(key);
}
}
}
swaggerDoc.paths = swaggerDoc.paths.Count == 0 ? null : swaggerDoc.paths;
swaggerDoc.definitions = swaggerDoc.paths == null ? null : swaggerDoc.definitions;
}
}
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Web API routes
config.MapHttpAttributeRoutes();
//config.Filters.Add(new ApiKeyFilter());
config.MessageHandlers.Add(new CustomAuthenticationMessageHandler());
}
}
public class SwaggerConfig
{
public static void Register()
{
GlobalConfiguration.Configuration
.EnableSwagger(c =>
{
c.SingleApiVersion("v1", "SwashbuckleExample");
c.DocumentFilter<AuthorizeRoleFilter>();
})
.EnableSwaggerUi(c => { });
}
}
附加
在我的项目中,我使用了一个CustomProvider,它根据API_KEY缓存Suggager Document。
public class CachingSwaggerProvider : ISwaggerProvider
{
private static ConcurrentDictionary<string, SwaggerDocument> _cache =
new ConcurrentDictionary<string, SwaggerDocument>();
private readonly ISwaggerProvider _swaggerProvider;
public CachingSwaggerProvider(ISwaggerProvider swaggerProvider)
{
_swaggerProvider = swaggerProvider;
}
public SwaggerDocument GetSwagger(string rootUrl, string apiVersion)
{
HttpContext httpContext = HttpContext.Current;
string name = httpContext.User.Identity.Name;
var cacheKey = string.Format("{0}_{1}_{2}", rootUrl, apiVersion, name);
return _cache.GetOrAdd(cacheKey, (key) => _swaggerProvider.GetSwagger(rootUrl, apiVersion));
}
}
本文展示了如何根据不同的用户角色,在登录之后来重定向到不同的页面。 在 method-security项目的基础上,我们构建了一个role-base-login项目。 build.gradle 修改 build.gradle 文件,让我们的role-base-login项目成为一个新的项目。 修改内容也比较简单,修改项目名称及版本即可。 jar { baseName = 'role-bas
问题内容: 我正在寻找有关其他人如何设计此方法的意见。我将提供基于类(Django组)的视图。 例如,用户组将确定他或她将有权访问哪些视图/模板。我正在考虑也许在表中存储用于查看功能的路径,以确定用户的链接栏将由什么组成。过滤器规范也可以存储,以确定哪些行将填充这些模板。 医院护理单位就是一个很好的例子。一个单位的护士不必看整个医院的病人。他们只需要去看病人。同一部门的医生也只需要看望那些患者,但
我正在用angular 4开发一个管理面板,并尝试集成一个部分来定制样式,比如change color、bg等。我已经开发了一个部分来保存数据库中的设置,使用API将它们作为json加载到应用程序中。 现在我正在尝试使用json中的值生成一个动态css,我尝试了主组件中的以下代码,但它不起作用 我不确定应该如何在组件中加载css值并在样式标记中使用它们。我没有找到任何其他的解决办法。 另一种方法是
问题内容: 是否可以使用任何基于角色的开源访问控制系统? 问题答案: 布兰登·萨维奇(Brandon Savage)在他的PHP软件包“ ApplicationACL ” 上做了一个演示,该演示可能会或可能不会完成基于角色的访问。PHPGACL可能也能正常工作,但是我不能肯定地告诉您。 但是,我可以告诉您的是Zend Framework 的Zend_ACL组件将执行基于角色的设置(但是您必须子类化
我在身份管理方面有一个项目,我希望有人能给我指出正确的方向。这是基于角色的配置,基本上我需要知道如何根据某些用户属性(例如职位、部门)配置特定的应用程序,然后自动为该应用程序提出配置请求。该应用程序是一个断开连接的应用程序,将手动配置。 我们试图实现的是,一旦在 OIM 中创建了用户,并且如果他或她满足这些条件,OIM 将生成对应用程序的请求,以便为它们预配它们。有没有办法在 OIM 中实现此目的
角色定义 [role_definition] 是RBAC角色继承关系的定义。 Casbin 支持 RBAC 系统的多个实例, 例如, 用户可以具有角色及其继承关系, 资源也可以具有角色及其继承关系。 这两个 RBAC 系统不会互相干扰。 此部分是可选的。 如果在模型中不使用 RBAC 角色, 则省略此部分。 [role_definition] g = _, _ g2 = _, _ 上述角色定义表