属性和自定义属性 - 授权如何工作?
Attributes and custom attributes - how does authorize work?
我正在尝试模仿 [Authorize]
属性,因为我发现您可以将一个属性粘贴在整个 class 之上,这很神奇,它以某种方式神奇地阻止了人们运行 class 中的方法,除非...某事...
我查看了创建自定义属性并找到了一些答案,这些答案基本上都是说除非我们使用反射,否则属性不可能阻止方法被调用,所以我决定深入研究 Authorize 属性,但只能找到元数据文件上的 "interface" 方法基本上
[Authorize]
属性到底在做什么?我如何实现属性以使用反射实际执行操作?例如。以下内容在归因于 class 时不执行任何操作:
[System.AttributeUsage(System.AttributeTargets.Class)]
public class Authorise : System.Attribute
{
public Authorise()
{
if (!SomeBoolCondition) throw new Exception ("Oh no!");
}
}
我不明白 Authorize 属性是如何检查然后将程序重定向到登录页面的。
如果您想使用自定义属性实现您自己的授权逻辑,您还需要在请求管道中创建和注册 middleware。您的中间件将接收整个 HttpContext,您可以使用它通过它的元数据检查端点的 CustomAuthorizeAttribute。从那里您可以实施授权逻辑并决定继续处理管道中的请求 "await next.Invoke()",或者停止处理和 return 对客户端的未授权响应。
属性class:
[AttributeUsage(AttributeTargets.Class)]
public class CustomAuthorizeAttribute : Attribute
{
public IEnumerable<string> AllowedUserRoles { get; private set; }
public CustomAuthorizeAttribute(params string[] allowedUserRoles)
{
this.AllowedUserRoles = allowedUserRoles.AsEnumerable();
}
}
具有自定义属性的控制器:
[ApiController]
[Route("[controller]")]
[CustomAuthorize("Admin", "Supervisor", "Worker")]
public class WeatherForecastController : ControllerBase
{
}
Startup.Configure 使用自定义中间件:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseRouting();
app.Use(async (httpContext, next) =>
{
var endpointMetaData = httpContext.GetEndpoint()
.Metadata;
bool hasCustomAuthorizeAttribute = endpointMetaData.Any(x => x is CustomAuthorizeAttribute);
if (hasCustomAuthorizeAttribute)
{
// get the endpoint's instance of CustomAuthorizeAttribute
CustomAuthorizeAttribute customAuthorieAttribute = endpointMetaData
.FirstOrDefault(x => x is CustomAuthorizeAttribute) as CustomAuthorizeAttribute;
// here you will have access to customAuthorizeAttribute.AllowedUserRoles
// and can execute your custom logic with it
bool isAuthorized = true;
if (isAuthorized)
{
// continue processing the request
await next.Invoke();
}
else
{
// stop processing request and return unauthorized response
httpContext.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
await httpContext.Response.WriteAsync("Unauthorized");
}
}
});
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
我正在尝试模仿 [Authorize]
属性,因为我发现您可以将一个属性粘贴在整个 class 之上,这很神奇,它以某种方式神奇地阻止了人们运行 class 中的方法,除非...某事...
我查看了创建自定义属性并找到了一些答案,这些答案基本上都是说除非我们使用反射,否则属性不可能阻止方法被调用,所以我决定深入研究 Authorize 属性,但只能找到元数据文件上的 "interface" 方法基本上
[Authorize]
属性到底在做什么?我如何实现属性以使用反射实际执行操作?例如。以下内容在归因于 class 时不执行任何操作:
[System.AttributeUsage(System.AttributeTargets.Class)]
public class Authorise : System.Attribute
{
public Authorise()
{
if (!SomeBoolCondition) throw new Exception ("Oh no!");
}
}
我不明白 Authorize 属性是如何检查然后将程序重定向到登录页面的。
如果您想使用自定义属性实现您自己的授权逻辑,您还需要在请求管道中创建和注册 middleware。您的中间件将接收整个 HttpContext,您可以使用它通过它的元数据检查端点的 CustomAuthorizeAttribute。从那里您可以实施授权逻辑并决定继续处理管道中的请求 "await next.Invoke()",或者停止处理和 return 对客户端的未授权响应。
属性class:
[AttributeUsage(AttributeTargets.Class)]
public class CustomAuthorizeAttribute : Attribute
{
public IEnumerable<string> AllowedUserRoles { get; private set; }
public CustomAuthorizeAttribute(params string[] allowedUserRoles)
{
this.AllowedUserRoles = allowedUserRoles.AsEnumerable();
}
}
具有自定义属性的控制器:
[ApiController]
[Route("[controller]")]
[CustomAuthorize("Admin", "Supervisor", "Worker")]
public class WeatherForecastController : ControllerBase
{
}
Startup.Configure 使用自定义中间件:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseRouting();
app.Use(async (httpContext, next) =>
{
var endpointMetaData = httpContext.GetEndpoint()
.Metadata;
bool hasCustomAuthorizeAttribute = endpointMetaData.Any(x => x is CustomAuthorizeAttribute);
if (hasCustomAuthorizeAttribute)
{
// get the endpoint's instance of CustomAuthorizeAttribute
CustomAuthorizeAttribute customAuthorieAttribute = endpointMetaData
.FirstOrDefault(x => x is CustomAuthorizeAttribute) as CustomAuthorizeAttribute;
// here you will have access to customAuthorizeAttribute.AllowedUserRoles
// and can execute your custom logic with it
bool isAuthorized = true;
if (isAuthorized)
{
// continue processing the request
await next.Invoke();
}
else
{
// stop processing request and return unauthorized response
httpContext.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
await httpContext.Response.WriteAsync("Unauthorized");
}
}
});
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}