[C#] ASP.NET Core에서 사용자 정의 AuthorizeAttribute를 어떻게 작성합니까?

ASP.NET Core에서 사용자 지정 권한 부여 특성을 만들려고합니다. 이전 버전에서는 재정의 할 수있었습니다 bool AuthorizeCore(HttpContextBase httpContext). 그러나에 더 이상 존재하지 않습니다 AuthorizeAttribute.

사용자 정의 AuthorizeAttribute를 작성하는 현재 방법은 무엇입니까?

내가 달성하려는 것 : 헤더 인증에서 세션 ID를 받고 있습니다. 그 ID에서 특정 작업이 유효한지 알 수 있습니다.



답변

ASP.Net Core 팀이 권장하는 접근 방식은 여기에 완전히 문서화 된 새로운 정책 설계를 사용하는 입니다. 새로운 접근 방식의 기본 아이디어는 새로운 [Authorize] 속성을 사용하여 “정책”을 지정하는 것입니다 (예 : [Authorize( Policy = "YouNeedToBe18ToDoThis")]정책이 응용 프로그램의 Startup.cs에 등록되어 일부 코드 블록을 실행하는 경우 (예 : 사용자에게 연령 주장이 있는지 확인) 나이가 18 세 이상인 경우).

정책 설계는 프레임 워크에 큰 도움이되며 ASP.Net Security Core 팀을 소개하도록 권장해야합니다. 즉, 모든 경우에 적합하지 않습니다. 이 접근 방식의 단점은 주어진 컨트롤러 또는 작업에 주어진 클레임 유형이 필요하다고 주장하는 가장 일반적인 요구에 편리한 솔루션을 제공 할 수 없다는 것입니다. 응용 프로그램에 개별 REST 리소스 ( “CanCreateOrder”, “CanReadOrder”, “CanUpdateOrder”, “CanDeleteOrder”등)에 대한 CRUD 작업을 관리하는 수백 개의 개별 권한이있을 수있는 경우 새로운 접근 방식에는 일대일 반복 작업이 필요합니다. 정책 이름과 클레임 이름 간 매핑 (예 :options.AddPolicy("CanUpdateOrder", policy => policy.RequireClaim(MyClaimTypes.Permission, "CanUpdateOrder));) 또는 런타임에 이러한 등록을 수행하기위한 코드 작성 (예 : 데이터베이스에서 모든 클레임 유형을 읽고 위에서 언급 한 호출을 루프로 수행). 대부분의 경우이 접근 방식의 문제점은 불필요한 오버 헤드라는 것입니다.

ASP.Net Core Security 팀은 자체 솔루션을 만들지 말 것을 권장하지만 경우에 따라 가장 신중한 옵션이 될 수 있습니다.

다음은 IAuthorizationFilter를 사용하여 지정된 컨트롤러 또는 작업에 대한 클레임 요구 사항을 표현하는 간단한 방법을 제공하는 구현입니다.

public class ClaimRequirementAttribute : TypeFilterAttribute
{
    public ClaimRequirementAttribute(string claimType, string claimValue) : base(typeof(ClaimRequirementFilter))
    {
        Arguments = new object[] {new Claim(claimType, claimValue) };
    }
}

public class ClaimRequirementFilter : IAuthorizationFilter
{
    readonly Claim _claim;

    public ClaimRequirementFilter(Claim claim)
    {
        _claim = claim;
    }

    public void OnAuthorization(AuthorizationFilterContext context)
    {
        var hasClaim = context.HttpContext.User.Claims.Any(c => c.Type == _claim.Type && c.Value == _claim.Value);
        if (!hasClaim)
        {
            context.Result = new ForbidResult();
        }
    }
}


[Route("api/resource")]
public class MyController : Controller
{
    [ClaimRequirement(MyClaimTypes.Permission, "CanReadResource")]
    [HttpGet]
    public IActionResult GetResource()
    {
        return Ok();
    }
}


답변