我试图使一个自定义授权属性在ASP。净的核心。在以前的版本中,可以重写bool AuthorizeCore(HttpContextBase httpContext)。但是这在AuthorizeAttribute中不再存在。
当前制作自定义AuthorizeAttribute的方法是什么?
我想要完成的:我正在头授权中接收会话ID。通过该ID,我将知道特定操作是否有效。
我试图使一个自定义授权属性在ASP。净的核心。在以前的版本中,可以重写bool AuthorizeCore(HttpContextBase httpContext)。但是这在AuthorizeAttribute中不再存在。
当前制作自定义AuthorizeAttribute的方法是什么?
我想要完成的:我正在头授权中接收会话ID。通过该ID,我将知道特定操作是否有效。
当前回答
我一直在寻找解决一个非常类似的问题,并决定创建一个自定义ActionFilterAttribute(我将其称为AuthorizationFilterAttribute)而不是AuthorizeAttribute来实现此处的指导:https://learn.microsoft.com/en-us/aspnet/core/security/authorization/resourcebased?view=aspnetcore-6.0#challenge-and-forbid-with-an-operational-resource-handler。
其他回答
当前制作自定义AuthorizeAttribute的方法是什么
对于纯授权场景(例如仅限制特定用户访问),建议使用新的授权块:https://github.com/aspnet/MusicStore/blob/1c0aeb08bb1ebd846726232226279bbe001782e1/samples/MusicStore/Startup.cs#L84-L92
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.Configure<AuthorizationOptions>(options =>
{
options.AddPolicy("ManageStore", policy => policy.RequireClaim("Action", "ManageStore"));
});
}
}
public class StoreController : Controller
{
[Authorize(Policy = "ManageStore"), HttpGet]
public async Task<IActionResult> Manage() { ... }
}
对于身份验证,最好在中间件级别进行处理。
你到底想达到什么目的?
我一直在寻找解决一个非常类似的问题,并决定创建一个自定义ActionFilterAttribute(我将其称为AuthorizationFilterAttribute)而不是AuthorizeAttribute来实现此处的指导:https://learn.microsoft.com/en-us/aspnet/core/security/authorization/resourcebased?view=aspnetcore-6.0#challenge-and-forbid-with-an-operational-resource-handler。
我是asp.net安全人员。首先,让我道歉,除了音乐存储样本或单元测试之外,这些都还没有被记录下来,而且还在公开的api方面进行改进。详细的文档在这里。
我们不希望您编写自定义授权属性。如果你需要这样做,我们做错了什么。相反,您应该编写授权需求。
授权作用于身份。身份通过认证创建。
You say in comments you want to check a session ID in a header. Your session ID would be the basis for identity. If you wanted to use the Authorize attribute you'd write an authentication middleware to take that header and turn it into an authenticated ClaimsPrincipal. You would then check that inside an authorization requirement. Authorization requirements can be as complicated as you like, for example here's one that takes a date of birth claim on the current identity and will authorize if the user is over 18;
public class Over18Requirement : AuthorizationHandler<Over18Requirement>, IAuthorizationRequirement
{
public override void Handle(AuthorizationHandlerContext context, Over18Requirement requirement)
{
if (!context.User.HasClaim(c => c.Type == ClaimTypes.DateOfBirth))
{
context.Fail();
return;
}
var dobVal = context.User.FindFirst(c => c.Type == ClaimTypes.DateOfBirth).Value;
var dateOfBirth = Convert.ToDateTime(dobVal);
int age = DateTime.Today.Year - dateOfBirth.Year;
if (dateOfBirth > DateTime.Today.AddYears(-age))
{
age--;
}
if (age >= 18)
{
context.Succeed(requirement);
}
else
{
context.Fail();
}
}
}
然后在ConfigureServices()函数中将其连接起来
services.AddAuthorization(options =>
{
options.AddPolicy("Over18",
policy => policy.Requirements.Add(new Authorization.Over18Requirement()));
});
最后,将它应用到控制器或动作方法
[Authorize(Policy = "Over18")]
下面是一个简单的5步指南,教你如何使用策略来实现自定义角色授权:)。我使用了这些文档。
创建需求:
public class RoleRequirement : IAuthorizationRequirement
{
public string Role { get; set; }
}
创建一个处理器:
public class RoleHandler : AuthorizationHandler<RoleRequirement>
{
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, RoleRequirement requirement)
{
var requiredRole = requirement.Role;
//custom auth logic
// you can use context to access authenticated user,
// you can use dependecy injection to call custom services
var hasRole = true;
if (hasRole)
{
context.Succeed(requirement);
}
else
{
context.Fail(new AuthorizationFailureReason(this, $"Role {requirement.Role} missing"));
}
}
}
在Program.cs中添加处理器:
builder.Services.AddSingleton<IAuthorizationHandler, RoleHandler>();
在program.cs中添加带有角色需求的策略:
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("Read", policy => policy.Requirements.Add(new RoleRequirement{Role = "ReadAccess_Custom_System"}));
});
使用你的策略:
[Authorize("Read")]
public class ExampleController : ControllerBase
{
}
为了在我们的应用程序中进行授权。我们必须根据在授权属性中传递的参数调用服务。
例如,如果我们想检查登录的医生是否可以查看病人的预约,我们将传递“View_Appointment”到自定义授权属性,并在DB服务中检查该权利,并根据结果进行审查。下面是这个场景的代码:
public class PatientAuthorizeAttribute : TypeFilterAttribute
{
public PatientAuthorizeAttribute(params PatientAccessRights[] right) : base(typeof(AuthFilter)) //PatientAccessRights is an enum
{
Arguments = new object[] { right };
}
private class AuthFilter : IActionFilter
{
PatientAccessRights[] right;
IAuthService authService;
public AuthFilter(IAuthService authService, PatientAccessRights[] right)
{
this.right = right;
this.authService = authService;
}
public void OnActionExecuted(ActionExecutedContext context)
{
}
public void OnActionExecuting(ActionExecutingContext context)
{
var allparameters = context.ActionArguments.Values;
if (allparameters.Count() == 1)
{
var param = allparameters.First();
if (typeof(IPatientRequest).IsAssignableFrom(param.GetType()))
{
IPatientRequest patientRequestInfo = (IPatientRequest)param;
PatientAccessRequest userAccessRequest = new PatientAccessRequest();
userAccessRequest.Rights = right;
userAccessRequest.MemberID = patientRequestInfo.PatientID;
var result = authService.CheckUserPatientAccess(userAccessRequest).Result; //this calls DB service to check from DB
if (result.Status == ReturnType.Failure)
{
//TODO: return apirepsonse
context.Result = new StatusCodeResult((int)System.Net.HttpStatusCode.Forbidden);
}
}
else
{
throw new AppSystemException("PatientAuthorizeAttribute not supported");
}
}
else
{
throw new AppSystemException("PatientAuthorizeAttribute not supported");
}
}
}
}
在API操作中,我们像这样使用它:
[PatientAuthorize(PatientAccessRights.PATIENT_VIEW_APPOINTMENTS)] //this is enum, we can pass multiple
[HttpPost]
public SomeReturnType ViewAppointments()
{
}