คุณจะสร้าง AuthorizeAttribute แบบกำหนดเองใน ASP.NET Core ได้อย่างไร


428

ฉันกำลังพยายามสร้างแอตทริบิวต์การให้สิทธิ์ที่กำหนดเองใน ASP.NET Core bool AuthorizeCore(HttpContextBase httpContext)ในรุ่นก่อนหน้ามันเป็นไปได้ที่จะแทนที่ AuthorizeAttributeแต่ตอนนี้ไม่ได้อยู่ใน

แนวทางปัจจุบันในการสร้าง AuthorizeAttribute แบบกำหนดเองคืออะไร

สิ่งที่ฉันพยายามทำให้สำเร็จ: ฉันได้รับรหัสเซสชันในการให้สิทธิ์ส่วนหัว จาก ID นั้นฉันจะรู้ว่าการกระทำบางอย่างนั้นถูกต้องหรือไม่


ฉันไม่แน่ใจว่าจะทำอย่างไร แต่ MVC เป็นโอเพ่นซอร์ส คุณสามารถดึง repo GitHub และมองหาการใช้งานของ IAuthorizationFilter ถ้าฉันมีเวลาวันนี้ฉันจะตามหาคุณและโพสต์คำตอบจริง แต่ไม่มีสัญญา repo github: github.com/aspnet/Mvc
bopapa_1979

ตกลงจากเวลา แต่ดูสำหรับประเพณีของ AuthorizationPolicy ใน MVC Repo ซึ่งใช้ AuthorizeAttribute ใน aspnet / การรักษาความปลอดภัย repo นี่: github.com/aspnet/Security อีกวิธีหนึ่งคือค้นหาใน repository MVC สำหรับเนมสเปซที่สิ่งที่คุณสนใจเกี่ยวกับความปลอดภัยซึ่งก็คือ Microsoft.AspNet.Authorization ขออภัยฉันไม่สามารถช่วยเหลือได้มากกว่านี้ โชคดี!
bopapa_1979

คำตอบ:


446

วิธีที่แนะนำโดยทีมงาน ASP.Net หลักคือการใช้การออกแบบนโยบายใหม่ซึ่งเป็นเอกสารอย่างเต็มที่ที่นี่ แนวคิดพื้นฐานที่อยู่เบื้องหลังวิธีการใหม่คือการใช้แอตทริบิวต์ [อนุญาต] ใหม่เพื่อกำหนด "นโยบาย" (เช่น[Authorize( Policy = "YouNeedToBe18ToDoThis")]เมื่อนโยบายถูกลงทะเบียนไว้ใน Startup.cs ของแอปพลิเคชันเพื่อดำเนินการบล็อกบางส่วนของรหัส (เช่นให้แน่ใจว่าผู้ใช้มีการอ้างสิทธิ์อายุ) ที่อายุ 18 หรือมากกว่า)

การออกแบบนโยบายเป็นการเพิ่มเติมที่ยอดเยี่ยมสำหรับกรอบงานและทีม ASP.Net Security Core ควรได้รับคำชมสำหรับการแนะนำ ที่กล่าวว่ามันไม่เหมาะสำหรับทุกกรณี ข้อบกพร่องของวิธีนี้คือมันไม่สามารถให้วิธีแก้ปัญหาที่สะดวกสำหรับความต้องการที่พบได้บ่อยที่สุดเพียงยืนยันว่าคอนโทรลเลอร์หรือการกระทำที่กำหนดต้องใช้ประเภทการอ้างสิทธิ์ที่กำหนด ในกรณีที่แอปพลิเคชันอาจมีสิทธิ์แบบไม่ต่อเนื่องหลายร้อยรายการที่ควบคุมการดำเนินการ CRUD ในทรัพยากร REST แต่ละรายการ ("CanCreateOrder", "CanReadOrder", "CanUpdateOrder", "CanDeleteOrder" ฯลฯ ) วิธีการใหม่นั้นต้องการการทำซ้ำแบบหนึ่งต่อหนึ่ง การแมปหนึ่งครั้งระหว่างชื่อนโยบายและชื่อการอ้างสิทธิ์ (เช่น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();
    }
}

78
สิ่งนี้ควรถูกทำเครื่องหมายเป็นคำตอบที่ถูกต้อง ที่นี่คุณจะเห็นว่าผู้คนใน Microsoft พิจารณาความคิดเห็นของผู้พัฒนาอย่างไร ฉันไม่เข้าใจเหตุผลที่พวกเขา "ใจแคบ" จัดการเรื่องนี้เนื่องจากเป็นสถานการณ์ที่พบได้บ่อยมากที่จะมีการอนุญาตที่แตกต่างกันมากมายการกำหนดรหัสนโยบายหนึ่งรายการสำหรับแต่ละรายการนั้นเป็นเรื่องที่สมบูรณ์เกินไป ฉันกำลังมองหาสิ่งนี้มาเป็นเวลานาน ... (ฉันถามคำถามนี้ไปแล้วเมื่อเกือบสองปีที่แล้วเมื่อ vNext ยังคงวางเดิมพันที่นี่: stackoverflow.com/questions/32181400/แต่เรายังติดอยู่ที่นั่น)
Vi100

3
นี่คือสิ่งที่ดี เรามีมิดเดิลแวร์การรับรองความถูกต้องบน Web API แต่มีการรักษาความปลอดภัยให้กับสิทธิ์การอนุญาตตามบทบาท ดังนั้นต้องเพียงแค่โยนในคุณลักษณะเช่น: [MyAuthorize (MyClaimTypes.Permission, MyClaimValueTypes.Write, MyPermission.Employee)] ดูดีมาก
Mariano Peinador

4
@Derek Greer: นี่คือคำตอบที่ดีที่สุด อย่างไรก็ตามคุณจะใช้ ActionFilter ซึ่งทำงานหลังจากให้สิทธิ์ตัวกรองการดำเนินการ อย่างไรก็ตามมีการใช้งานและอนุญาตตัวกรองการกระทำหรือไม่
ยาโคบฟาน

6
@JacobPhan คุณถูกต้องสิ่งนี้จะถูกนำไปใช้งานได้ดีขึ้นโดยใช้อินเทอร์เฟซ IAuthorizationFilter ฉันได้อัปเดตรหัสเพื่อให้สอดคล้องกับการเปลี่ยนแปลง
Derek Greer

3
จึงnew ForbidResult()ไม่ทำงาน (ทำให้เกิดข้อยกเว้น / 500) เนื่องจากไม่มีรูปแบบการให้สิทธิ์ที่เกี่ยวข้อง ฉันจะใช้อะไรกับกรณีนี้
Sinaesthetic

252

ฉันเป็นคนที่รักษาความปลอดภัย asp.net ก่อนอื่นฉันต้องขออภัยด้วยที่ไม่มีเอกสารใดนอกเหนือจากตัวอย่างเพลงหรือการทดสอบหน่วยเก็บเพลงและยังคงได้รับการปรับปรุงในแง่ของ API ที่เปิดเผย เอกสารรายละเอียดเป็นที่นี่

เราไม่ต้องการให้คุณเขียนแอตทริบิวต์การให้สิทธิ์ที่กำหนดเอง หากคุณต้องทำสิ่งนั้นเราได้ทำอะไรผิดไป คุณควรเขียนข้อกำหนดการให้สิทธิ์แทน

การอนุญาตให้กระทำตามตัวตน อัตลักษณ์ถูกสร้างขึ้นโดยการตรวจสอบ

คุณพูดในความคิดเห็นที่คุณต้องการตรวจสอบ ID เซสชั่นในส่วนหัว รหัสเซสชันของคุณจะเป็นข้อมูลพื้นฐานสำหรับการระบุตัวตน หากคุณต้องการใช้แอตทริบิวต์ที่คุณต้องการเขียนตัวกลางการตรวจสอบจะใช้ส่วนหัวที่และเปิดเป็นรับรองความถูกต้องAuthorize ClaimsPrincipalจากนั้นคุณจะตรวจสอบว่าภายในข้อกำหนดการให้สิทธิ์ ข้อกำหนดการอนุญาตอาจมีความซับซ้อนได้ตามที่คุณต้องการตัวอย่างเช่นข้อกำหนดการให้สิทธิ์วันเกิดที่ระบุตัวตนปัจจุบันและจะอนุญาตหากผู้ใช้อายุเกิน 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 dateOfBirth = Convert.ToDateTime(context.User.FindFirst(c => c.Type == ClaimTypes.DateOfBirth).Value);
            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")]

84
ฉันสงสัยว่า ... เราจะใช้การควบคุมการเข้าถึงแบบละเอียดได้อย่างไร สมมติว่าความManageStoreต้องการจากตัวอย่างร้านค้าเพลง ในตัวอย่างมีวิธี "อนุญาตทั้งหมดหรือไม่มี" อย่างใดอย่างหนึ่งเท่านั้น จากนั้นเราต้องสร้างนโยบายใหม่สำหรับการเปลี่ยนแปลงที่เป็นไปได้ทุกครั้งหรือไม่? เช่น "ผู้ใช้ / อ่าน", "ผู้ใช้ / สร้าง", "ผู้ใช้ / AssignRole", "ผู้ใช้ / ลบ" หากเราต้องการเคลมอย่างละเอียด? ฟังดูคล้ายกับงานติดตั้งที่ใช้งานได้จริงและนโยบายที่มากมายเพียงจัดการข้อเรียกร้องแทนที่จะเป็น[ClaimsAutzorization("User", "Read", "Create", "Delete", "Assign")]คุณลักษณะใช่ไหม
Tseng

84
ฉันต้องแสดงความคิดเห็นว่าทั้งหมดนี้ซับซ้อนกว่าการใช้วิธีการให้สิทธิ์ที่กำหนดเอง ฉันรู้ว่าฉันต้องการการอนุญาตให้ทำได้ฉันสามารถไปและเขียนใน MVC 5 ใน MVC 6 พวกเขาเพิ่มโค้ด "เสร็จสิ้น" จำนวนมากที่ซับซ้อนกว่าที่จะเข้าใจจริง ๆ ทำให้ฉันนั่งอยู่หน้าหน้าพยายามคิดอะไรบางอย่างแทนที่จะเขียนโค้ดให้ถูกต้องและยังเป็นปัญหาใหญ่สำหรับผู้ที่ใช้ RDBMS นอกเหนือจาก Microsoft (หรือ No-Sql)
Felype

17
จากมุมมองของฉันนี้ไม่ได้แก้สถานการณ์ทั้งหมด ก่อนหน้า MVC 6 ฉันใช้แอตทริบิวต์อนุญาตที่กำหนดเองเพื่อใช้ "ระบบอนุญาต" ของฉันเอง ฉันสามารถเพิ่มคุณสมบัติอนุญาตให้ทุกการกระทำและผ่านการอนุญาตที่จำเป็นหนึ่งรายการ (เป็น Enum-Value) สิทธิ์ของตัวเองถูกแมปกับกลุ่ม / ผู้ใช้ภายในฐานข้อมูล ดังนั้นฉันไม่เห็นวิธีจัดการกับนโยบายนี้!
Gerwald

43
ฉันเหมือนกับคนอื่น ๆ ในความคิดเห็นเหล่านี้รู้สึกผิดหวังอย่างมากที่การใช้คุณลักษณะสำหรับการให้สิทธิ์ได้รับความนิยมอย่างมากในสิ่งที่เป็นไปได้ใน Web API 2 ขออภัยพวกคุณ แต่สิ่งที่เป็นนามธรรม "ข้อกำหนด" ของคุณ พารามิเตอร์ตัวสร้างคุณลักษณะเพื่อแจ้งให้ทราบขั้นตอนวิธีการอนุญาตพื้นฐาน [CustomAuthorize(Operator.And, Permission.GetUser, Permission.ModifyUser)]จะใช้เป็นสมองที่ตายง่ายที่จะทำสิ่งที่ชอบ ฉันสามารถใช้แอตทริบิวต์ที่กำหนดเองเดียวได้หลายวิธีโดยการปรับเปลี่ยนพารามิเตอร์ Constructor
NathanAldenSr

61
ฉันก็ตกใจเช่นกันที่ว่า "ผู้นำการรักษาความปลอดภัยของ ASP.NET ASP.NET" ที่ประกาศตัวเองนั้นจริง ๆ แล้วแนะนำให้ใช้สายอักขระเวท (แฮ็คความหมายของIAuthorizeData.Policy) และผู้ให้บริการนโยบายที่กำหนดเองเพื่อเอาชนะการกำกับดูแลที่ชัดเจนนี้ ฉันคิดว่าเราไม่ควรที่จะสร้างการใช้งานของเราเอง? คุณไม่ได้เลือกเราหลายคนยกเว้นการใช้การอนุมัติอีกครั้งตั้งแต่เริ่มต้น (อีกครั้ง) และครั้งนี้โดยไม่ได้รับประโยชน์จากAuthorizeแอตทริบิวต์เก่าของ Web API ตอนนี้เราต้องทำกับตัวกรองการกระทำหรือระดับมิดเดิลแวร์
NathanAldenSr

104

ดูเหมือนว่าด้วย ASP.NET Core 2 คุณสามารถสืบทอดได้อีกครั้งAuthorizeAttributeคุณเพียงแค่ต้องใช้IAuthorizationFilter(หรือIAsyncAuthorizationFilter):

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
public class CustomAuthorizeAttribute : AuthorizeAttribute, IAuthorizationFilter
{
    private readonly string _someFilterParameter;

    public CustomAuthorizeAttribute(string someFilterParameter)
    {
        _someFilterParameter = someFilterParameter;
    }

    public void OnAuthorization(AuthorizationFilterContext context)
    {
        var user = context.HttpContext.User;

        if (!user.Identity.IsAuthenticated)
        {
            // it isn't needed to set unauthorized result 
            // as the base class already requires the user to be authenticated
            // this also makes redirect to a login page work properly
            // context.Result = new UnauthorizedResult();
            return;
        }

        // you can also use registered services
        var someService = context.HttpContext.RequestServices.GetService<ISomeService>();

        var isAuthorized = someService.IsUserAuthorized(user.Identity.Name, _someFilterParameter);
        if (!isAuthorized)
        {
            context.Result = new StatusCodeResult((int)System.Net.HttpStatusCode.Forbidden);
            return;
        }
    }
}

4
ดังนั้นคุณสามารถใช้สิ่งนี้เพื่อปฏิเสธการให้สิทธิ์ไม่ใช่ให้หรือไม่
MEMark

1
@MEMark เมื่อให้หมายถึงคุณหมายถึงการยกเลิกคุณสมบัติการอนุญาตอื่นหรือไม่
gius

2
AFAIK อนุญาตให้เข้าถึงได้โดยค่าเริ่มต้นดังนั้นคุณต้องปฏิเสธอย่างชัดเจน (เช่นโดยการเพิ่ม AuthorizeAttribute) ตรวจสอบคำถามนี้สำหรับรายละเอียดเพิ่มเติม: stackoverflow.com/questions/17272422/…
gius

16
โปรดทราบว่าในตัวอย่างที่แนะนำไม่จำเป็นต้องสืบทอดจาก AuthorizeAttribute คุณสามารถรับมรดกจากแอตทริบิวต์และIAuthorizationFilter วิธีนี้คุณจะไม่ได้รับข้อยกเว้นต่อไปนี้หากใช้กลไกการพิสูจน์ตัวตนที่ไม่ได้มาตรฐาน: InvalidOperationException: ไม่ได้ระบุ authenticationScheme และไม่พบ DefaultChallengeScheme
Anatolyevich

13
โปรดทราบว่าถ้าคุณOnAuthorizationดำเนินการจำเป็นต้องรอวิธี async คุณควรใช้IAsyncAuthorizationFilterแทนIAuthorizationFilterมิฉะนั้นตัวกรองของคุณจะดำเนินการพร้อมกันและการกระทำการควบคุมของคุณจะดำเนินการไม่คำนึงถึงผลของตัวกรอง
Codemunkie

34

จากคำตอบของDerek Greer GREAT ที่ดีฉันก็ทำได้ด้วย enums

นี่คือตัวอย่างของรหัสของฉัน:

public enum PermissionItem
{
    User,
    Product,
    Contact,
    Review,
    Client
}

public enum PermissionAction
{
    Read,
    Create,
}


public class AuthorizeAttribute : TypeFilterAttribute
{
    public AuthorizeAttribute(PermissionItem item, PermissionAction action)
    : base(typeof(AuthorizeActionFilter))
    {
        Arguments = new object[] { item, action };
    }
}

public class AuthorizeActionFilter : IAuthorizationFilter
{
    private readonly PermissionItem _item;
    private readonly PermissionAction _action;
    public AuthorizeActionFilter(PermissionItem item, PermissionAction action)
    {
        _item = item;
        _action = action;
    }
    public void OnAuthorization(AuthorizationFilterContext context)
    {
        bool isAuthorized = MumboJumboFunction(context.HttpContext.User, _item, _action); // :)

        if (!isAuthorized)
        {
            context.Result = new ForbidResult();
        }
    }
}

public class UserController : BaseController
{
    private readonly DbContext _context;

    public UserController( DbContext context) :
        base()
    {
        _logger = logger;
    }

    [Authorize(PermissionItem.User, PermissionAction.Read)]
    public async Task<IActionResult> Index()
    {
        return View(await _context.User.ToListAsync());
    }
}

1
ขอบคุณสำหรับสิ่งนี้. ฉันสร้างโพสต์นี้ด้วยการนำไปใช้ที่แตกต่างกันเล็กน้อยและคำขอตรวจสอบstackoverflow.com/questions/49551047/…
Anton Swanevelder

2
MumboJumboFunction <3
Marek Urbanowicz

31

คุณสามารถสร้าง AuthorizationHandler ของคุณเองที่จะค้นหาแอตทริบิวต์ที่กำหนดเองในตัวควบคุมและการกระทำของคุณและส่งไปยังวิธีการ HandleRequirementAsync

public abstract class AttributeAuthorizationHandler<TRequirement, TAttribute> : AuthorizationHandler<TRequirement> where TRequirement : IAuthorizationRequirement where TAttribute : Attribute
{
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, TRequirement requirement)
    {
        var attributes = new List<TAttribute>();

        var action = (context.Resource as AuthorizationFilterContext)?.ActionDescriptor as ControllerActionDescriptor;
        if (action != null)
        {
            attributes.AddRange(GetAttributes(action.ControllerTypeInfo.UnderlyingSystemType));
            attributes.AddRange(GetAttributes(action.MethodInfo));
        }

        return HandleRequirementAsync(context, requirement, attributes);
    }

    protected abstract Task HandleRequirementAsync(AuthorizationHandlerContext context, TRequirement requirement, IEnumerable<TAttribute> attributes);

    private static IEnumerable<TAttribute> GetAttributes(MemberInfo memberInfo)
    {
        return memberInfo.GetCustomAttributes(typeof(TAttribute), false).Cast<TAttribute>();
    }
}

จากนั้นคุณสามารถใช้มันสำหรับแอตทริบิวต์ที่กำหนดเองใด ๆ ที่คุณต้องการในตัวควบคุมหรือการกระทำของคุณ ตัวอย่างเช่นการเพิ่มข้อกำหนดการอนุญาต เพียงสร้างแอตทริบิวต์ที่กำหนดเองของคุณ

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]
public class PermissionAttribute : AuthorizeAttribute
{
    public string Name { get; }

    public PermissionAttribute(string name) : base("Permission")
    {
        Name = name;
    }
}

จากนั้นสร้างความต้องการเพื่อเพิ่มในนโยบายของคุณ

public class PermissionAuthorizationRequirement : IAuthorizationRequirement
{
    //Add any custom requirement properties if you have them
}

จากนั้นสร้าง AuthorizationHandler สำหรับแอตทริบิวต์ที่กำหนดเองของคุณโดยสืบทอด AttributeAuthorizationHandler ที่เราสร้างไว้ก่อนหน้านี้ มันจะถูกส่งผ่าน IEnumerable สำหรับแอตทริบิวต์ที่กำหนดเองทั้งหมดของคุณในวิธีการ HandleRequirementsAsync ที่สะสมจากคอนโทรลเลอร์และแอคชั่นของคุณ

public class PermissionAuthorizationHandler : AttributeAuthorizationHandler<PermissionAuthorizationRequirement, PermissionAttribute>
{
    protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, PermissionAuthorizationRequirement requirement, IEnumerable<PermissionAttribute> attributes)
    {
        foreach (var permissionAttribute in attributes)
        {
            if (!await AuthorizeAsync(context.User, permissionAttribute.Name))
            {
                return;
            }
        }

        context.Succeed(requirement);
    }

    private Task<bool> AuthorizeAsync(ClaimsPrincipal user, string permission)
    {
        //Implement your custom user permission logic here
    }
}

และในที่สุดใน Startup.cs ของคุณวิธี ConfigureServices เพิ่ม AuthorizationHandler ที่กำหนดเองของคุณไปยังบริการและเพิ่มนโยบายของคุณ

        services.AddSingleton<IAuthorizationHandler, PermissionAuthorizationHandler>();

        services.AddAuthorization(options =>
        {
            options.AddPolicy("Permission", policyBuilder =>
            {
                policyBuilder.Requirements.Add(new PermissionAuthorizationRequirement());
            });
        });

ตอนนี้คุณสามารถตกแต่งตัวควบคุมและการกระทำของคุณด้วยแอตทริบิวต์ที่กำหนดเองของคุณ

[Permission("AccessCustomers")]
public class CustomersController
{
    [Permission("AddCustomer")]
    IActionResult AddCustomer([FromBody] Customer customer)
    {
        //Add customer
    }
}

1
ฉันจะดูที่ ASAP นี้
NathanAldenSr

5
นี่คือ overengineered ... ฉันแก้ไขเดียวกันโดยใช้ AuthorizationFilterAttribute ง่าย ๆ ซึ่งได้รับพารามิเตอร์ คุณไม่ต้องการการไตร่ตรองสำหรับเรื่องนี้ดูเหมือนว่าจะดุร้ายยิ่งกว่าโซลูชัน "ทางการ" (ที่ฉันพบว่าค่อนข้างแย่)
Vi100

2
@ Vi100 ฉันไม่สามารถหาข้อมูลเกี่ยวกับ AuthorizationFilters ได้มากใน ASP.NET Core หน้าเอกสารอย่างเป็นทางการกล่าวว่าพวกเขากำลังทำงานในหัวข้อนี้ docs.microsoft.com/en-us/aspnet/core/security/authorization/…
Shawn

4
@ Vi100 คุณช่วยแบ่งปันวิธีแก้ปัญหาของคุณได้ไหมถ้ามีวิธีที่ง่ายกว่าในการทำสิ่งนี้ให้สำเร็จฉันอยากจะรู้
Shawn

2
สิ่งหนึ่งที่ควรสังเกตการใช้ UnderlyingSystemType ข้างต้นไม่ได้รวบรวม แต่ดูเหมือนว่าการลบจะใช้งานได้
ชา

25

อะไรคือวิธีการในปัจจุบันเพื่อสร้าง AuthorizeAttribute ที่กำหนดเอง

ง่าย: AuthorizeAttributeไม่ต้องสร้างของคุณเอง

สำหรับสถานการณ์การอนุญาตที่แท้จริง (เช่นการ จำกัด การเข้าถึงเฉพาะผู้ใช้เท่านั้น) แนวทางที่แนะนำคือการใช้บล็อกการอนุญาตใหม่: https://github.com/aspnet/MusicStore/blob/1c0aeb08bb1ebd846726232226279bbe001782e1/samples/MusicStore/Stupup.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() { ... }
}

สำหรับการตรวจสอบสิทธิ์จะมีการจัดการที่ดีที่สุดในระดับมิดเดิลแวร์

คุณพยายามทำอะไรให้สำเร็จ


1
ฉันได้รับรหัสเซสชันในการให้สิทธิ์ส่วนหัว จาก ID นั้นฉันจะรู้ว่าการกระทำบางอย่างนั้นถูกต้องหรือไม่
jltrem

1
นั่นไม่ใช่ข้อกังวลเกี่ยวกับการอนุญาต ฉันเดาว่า "session ID" ของคุณเป็นโทเค็นที่มีตัวตนของผู้โทร: สิ่งนี้ควรทำในระดับมิดเดิลแวร์
Kévin Chalet

3
ไม่ใช่การพิสูจน์ตัวตน (การกำหนดว่าใครเป็นผู้ใช้) แต่เป็นการอนุญาต (การพิจารณาว่าผู้ใช้ควรมีสิทธิ์เข้าถึงทรัพยากรหรือไม่) ดังนั้นคุณแนะนำให้ฉันดูที่จะแก้ปัญหานี้ได้อย่างไร
jltrem

3
@ jltrem เห็นด้วยสิ่งที่คุณกำลังพูดถึงคือการอนุญาตไม่ใช่การรับรองความถูกต้อง
bopapa_1979

2
@Pinpoint ฉันไม่ได้ ฉันค้นหาระบบอื่นสำหรับข้อมูลนั้น ระบบนั้นรับรองความถูกต้อง (กำหนดผู้ใช้) และอนุญาต (บอกฉันว่าผู้ใช้นั้นสามารถเข้าถึง) ได้อย่างไร ตอนนี้ฉันแฮ็คมันทำงานโดยการเรียกวิธีการในการควบคุมแต่ละการกระทำเพื่อให้ระบบอื่นตรวจสอบเซสชั่น ฉันต้องการให้สิ่งนี้เกิดขึ้นโดยอัตโนมัติผ่านแอตทริบิวต์
jltrem

4

หากใครก็ตามที่ต้องการตรวจสอบโทเค็นผู้ถือในขั้นตอนอนุญาตให้ใช้แนวทางปฏิบัติด้านความปลอดภัยในปัจจุบันที่คุณสามารถทำได้

เพิ่มสิ่งนี้ลงใน Startup / ConfigureServices ของคุณ

    services.AddSingleton<IAuthorizationHandler, BearerAuthorizationHandler>();
    services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer();

    services.AddAuthorization(options => options.AddPolicy("Bearer",
        policy => policy.AddRequirements(new BearerRequirement())
        )
    );

และสิ่งนี้ใน codebase ของคุณ

public class BearerRequirement : IAuthorizationRequirement
{
    public async Task<bool> IsTokenValid(SomeValidationContext context, string token)
    {
        // here you can check if the token received is valid 
        return true;
    }
}

public class BearerAuthorizationHandler : AuthorizationHandler<BearerRequirement> 
{

    public BearerAuthorizationHandler(SomeValidationContext thatYouCanInject)
    {
       ...
    }

    protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, BearerRequirement requirement)
    {
        var authFilterCtx = (Microsoft.AspNetCore.Mvc.Filters.AuthorizationFilterContext)context.Resource;
        string authHeader = authFilterCtx.HttpContext.Request.Headers["Authorization"];
        if (authHeader != null && authHeader.Contains("Bearer"))
        {
            var token = authHeader.Replace("Bearer ", string.Empty);
            if (await requirement.IsTokenValid(thatYouCanInject, token))
            {
                context.Succeed(requirement);
            }
        }
    }
}

หากรหัสไม่ถึงcontext.Succeed(...)จะล้มเหลวต่อไป (401)

และจากนั้นในตัวควบคุมของคุณคุณสามารถใช้

 [Authorize(Policy = "Bearer", AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]

ทำไมคุณถึงเลือกที่จะทำการตรวจสอบโทเค็นของคุณเองเมื่อมิดเดิลแวร์ JwtBearer ดูแลเรื่องนี้อยู่แล้ว? นอกจากนี้ยังวางเนื้อหาที่ถูกต้องในส่วนหัวการตอบกลับ WWW-Authenticate สำหรับความล้มเหลวในการตรวจสอบ / หมดอายุการตรวจสอบความถูกต้อง / โทเค็น หากคุณต้องการเข้าสู่ขั้นตอนการพิสูจน์ตัวตนมีเหตุการณ์เฉพาะคุณสามารถแตะที่ตัวเลือก AddJwtBearer (OnAuthenticationFailed, OnChallenge, OnMessageReceived และ OnTokenValidated)
Darren Lewis

นี่ง่ายกว่าโซลูชันอื่น ๆ ที่ฉันเคยเห็น โดยเฉพาะอย่างยิ่งสำหรับกรณีการใช้คีย์ API อย่างง่าย One update: สำหรับ 3.1 cast to AuthorizationFilterContext ไม่สามารถใช้งานได้อีกต่อไปเนื่องจากสิ่งที่กำหนดเส้นทางปลายทาง คุณต้องคว้าบริบทผ่าน HttpContextAccessor
JasonCoder

2

วิธีการที่ทันสมัยคือ AuthenticationHandlers

ใน startup.cs เพิ่ม

services.AddAuthentication("BasicAuthentication").AddScheme<AuthenticationSchemeOptions, BasicAuthenticationHandler>("BasicAuthentication", null);

public class BasicAuthenticationHandler : AuthenticationHandler<AuthenticationSchemeOptions>
    {
        private readonly IUserService _userService;

        public BasicAuthenticationHandler(
            IOptionsMonitor<AuthenticationSchemeOptions> options,
            ILoggerFactory logger,
            UrlEncoder encoder,
            ISystemClock clock,
            IUserService userService)
            : base(options, logger, encoder, clock)
        {
            _userService = userService;
        }

        protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
        {
            if (!Request.Headers.ContainsKey("Authorization"))
                return AuthenticateResult.Fail("Missing Authorization Header");

            User user = null;
            try
            {
                var authHeader = AuthenticationHeaderValue.Parse(Request.Headers["Authorization"]);
                var credentialBytes = Convert.FromBase64String(authHeader.Parameter);
                var credentials = Encoding.UTF8.GetString(credentialBytes).Split(new[] { ':' }, 2);
                var username = credentials[0];
                var password = credentials[1];
                user = await _userService.Authenticate(username, password);
            }
            catch
            {
                return AuthenticateResult.Fail("Invalid Authorization Header");
            }

            if (user == null)
                return AuthenticateResult.Fail("Invalid User-name or Password");

            var claims = new[] {
                new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
                new Claim(ClaimTypes.Name, user.Username),
            };
            var identity = new ClaimsIdentity(claims, Scheme.Name);
            var principal = new ClaimsPrincipal(identity);
            var ticket = new AuthenticationTicket(principal, Scheme.Name);

            return AuthenticateResult.Success(ticket);
        }
    }

IUserService เป็นบริการที่คุณสร้างขึ้นในที่ที่คุณมีชื่อผู้ใช้และรหัสผ่าน โดยพื้นฐานแล้วจะส่งคืนคลาสผู้ใช้ที่คุณใช้เพื่อจับคู่การอ้างสิทธิ์ของคุณ

var claims = new[] {
                new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
                new Claim(ClaimTypes.Name, user.Username),
            }; 

จากนั้นคุณสามารถสอบถามข้อเรียกร้องเหล่านี้และข้อมูลใด ๆ ที่คุณทำแผนที่ซึ่งค่อนข้างน้อยได้ดูคลาส ClaimTypes

คุณสามารถใช้วิธีนี้ในวิธีการเสริมและรับการแมปใดก็ได้

public int? GetUserId()
{
   if (context.User.Identity.IsAuthenticated)
    {
       var id=context.User.FindFirst(ClaimTypes.NameIdentifier);
       if (!(id is null) && int.TryParse(id.Value, out var userId))
            return userId;
     }
      return new Nullable<int>();
 }

วิธีใหม่นี้ฉันคิดว่าดีกว่า

public class BasicAuthenticationAttribute : AuthorizationFilterAttribute
{
    public override void OnAuthorization(HttpActionContext actionContext)
    {
        if (actionContext.Request.Headers.Authorization != null)
        {
            var authToken = actionContext.Request.Headers.Authorization.Parameter;
            // decoding authToken we get decode value in 'Username:Password' format
            var decodeauthToken = System.Text.Encoding.UTF8.GetString(Convert.FromBase64String(authToken));
            // spliting decodeauthToken using ':'
            var arrUserNameandPassword = decodeauthToken.Split(':');
            // at 0th postion of array we get username and at 1st we get password
            if (IsAuthorizedUser(arrUserNameandPassword[0], arrUserNameandPassword[1]))
            {
                // setting current principle
                Thread.CurrentPrincipal = new GenericPrincipal(new GenericIdentity(arrUserNameandPassword[0]), null);
            }
            else
            {
                actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized);
            }
        }
        else
        {
            actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized);
        }
    }

    public static bool IsAuthorizedUser(string Username, string Password)
    {
        // In this method we can handle our database logic here...
        return Username.Equals("test") && Password == "test";
    }
}

คำตอบที่ยอดเยี่ยมนี้ใช้งานได้อย่างมีเสน่ห์! ขอบคุณสำหรับสิ่งนั้นและฉันหวังว่าคุณจะได้รับการอัปเดตเนื่องจากเป็นคำตอบที่ดีที่สุดที่ฉันพบหลังจากใช้เวลาหกชั่วโมงในการค้นหาผ่านบล็อกเอกสารและสแต็กสำหรับการรับรองความถูกต้องเบื้องต้น
Piotr Śródka

@ PiotrŚródkaยินดีต้อนรับโปรดทราบว่าคำตอบคือ "ง่าย" เล็กน้อยทดสอบว่าคุณมี ':' ในข้อความในฐานะผู้ใช้ที่เป็นอันตรายสามารถลองและบริการของคุณโดยไม่เล่นตอนจบที่ดีในดัชนี ของข้อยกเว้นช่วง เช่นเคยทดสอบสิ่งที่มอบให้กับคุณโดยแหล่งข้อมูลภายนอก
Walter Vehoeven

2

จากการเขียนนี้ผมเชื่อว่าสิ่งนี้สามารถทำได้ด้วยส่วนต่อประสาน IClaimsTransformation ใน asp.net core 2 ขึ้นไป ฉันเพิ่งใช้การพิสูจน์แนวคิดที่สามารถแชร์ได้ที่นี่

public class PrivilegesToClaimsTransformer : IClaimsTransformation
{
    private readonly IPrivilegeProvider privilegeProvider;
    public const string DidItClaim = "http://foo.bar/privileges/resolved";

    public PrivilegesToClaimsTransformer(IPrivilegeProvider privilegeProvider)
    {
        this.privilegeProvider = privilegeProvider;
    }

    public async Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)
    {
        if (principal.Identity is ClaimsIdentity claimer)
        {
            if (claimer.HasClaim(DidItClaim, bool.TrueString))
            {
                return principal;
            }

            var privileges = await this.privilegeProvider.GetPrivileges( ... );
            claimer.AddClaim(new Claim(DidItClaim, bool.TrueString));

            foreach (var privilegeAsRole in privileges)
            {
                claimer.AddClaim(new Claim(ClaimTypes.Role /*"http://schemas.microsoft.com/ws/2008/06/identity/claims/role" */, privilegeAsRole));
            }
        }

        return principal;
    }
}

ที่จะใช้ในการควบคุมของคุณเพียงแค่เพิ่มที่เหมาะสม[Authorize(Roles="whatever")]กับวิธีการของคุณ

[HttpGet]
[Route("poc")]
[Authorize(Roles = "plugh,blast")]
public JsonResult PocAuthorization()
{
    var result = Json(new
    {
        when = DateTime.UtcNow,
    });

    result.StatusCode = (int)HttpStatusCode.OK;

    return result;
}

ในกรณีของเราทุกคำขอมีส่วนหัวการอนุญาตที่เป็น JWT นี่คือต้นแบบและฉันเชื่อว่าเราจะทำบางสิ่งที่ใกล้เคียงกับสิ่งนี้ในระบบการผลิตของเราในสัปดาห์หน้า

ผู้มีสิทธิเลือกตั้งในอนาคตพิจารณาวันที่เขียนเมื่อคุณลงคะแนน ณ วันนี้works on my machine.™ นี้คุณอาจต้องการการจัดการและบันทึกข้อผิดพลาดเพิ่มเติมในการใช้งานของคุณ


แล้ว ConfigureServices ล่ะ? จำเป็นต้องเพิ่มอะไรไหม?
แดเนียล

ตามที่กล่าวไว้ที่อื่นใช่
ไม่คืนเงินไม่มีผลตอบแทน

1

เพื่อขออนุมัติในแอพของเรา เราต้องเรียกใช้บริการตามพารามิเตอร์ที่ส่งผ่านในแอตทริบิวต์การให้สิทธิ์

ตัวอย่างเช่นหากเราต้องการตรวจสอบว่าแพทย์เข้าสู่ระบบสามารถดูการนัดหมายผู้ป่วยเราจะผ่าน "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()
    {

    }

1
โปรดทราบว่า IActionFilter จะมีปัญหาเมื่อคุณต้องการใช้คุณลักษณะเดียวกันสำหรับวิธีการของ Hub ใน SignalR.SignalR ฮับคาดว่า IAuthorizationFilter
ilkerkaran

ขอบคุณสำหรับข้อมูล. ฉันไม่ได้ใช้ SignalR ในแอปพลิเคชันของฉันในขณะนี้ดังนั้นฉันจึงยังไม่ได้ทดสอบกับมัน
อับดุลลาห์

หลักการเดียวกันฉันเดาว่าคุณจะต้องใช้รายการการอนุญาตของส่วนหัวการใช้งานจะแตกต่างกัน
Walter Vehoeven

0

คำตอบที่ได้รับการยอมรับ ( https://stackoverflow.com/a/41348219/4974715 ) นั้นไม่สามารถบำรุงรักษาตามความเป็นจริงหรือเหมาะสมได้เพราะ "CanReadResource" กำลังถูกใช้เป็นข้อเรียกร้อง (แต่ควรเป็นนโยบายในความเป็นจริง IMO) วิธีการที่คำตอบนั้นไม่ได้เป็นไปตามที่ใช้เพราะถ้าวิธีการดำเนินการต้องใช้การตั้งค่าการอ้างสิทธิ์ที่แตกต่างกันจำนวนมากดังนั้นด้วยคำตอบนั้นคุณต้องเขียนซ้ำ ๆ เช่น ...

[ClaimRequirement(MyClaimTypes.Permission, "CanReadResource")] 
[ClaimRequirement(MyClaimTypes.AnotherPermision, "AnotherClaimVaue")]
//and etc. on a single action.

ลองจินตนาการดูว่าจะต้องใช้รหัสเท่าใด โดยอุดมคติแล้ว "CanReadResource" ควรเป็นนโยบายที่ใช้การอ้างสิทธิ์จำนวนมากเพื่อพิจารณาว่าผู้ใช้สามารถอ่านทรัพยากรได้หรือไม่

สิ่งที่ฉันทำคือฉันสร้างนโยบายของฉันเป็นการนับแล้ววนซ้ำและตั้งค่าข้อกำหนดเช่นนี้ ...

services.AddAuthorization(authorizationOptions =>
        {
            foreach (var policyString in Enum.GetNames(typeof(Enumerations.Security.Policy)))
            {
                authorizationOptions.AddPolicy(
                    policyString,
                    authorizationPolicyBuilder => authorizationPolicyBuilder.Requirements.Add(new DefaultAuthorizationRequirement((Enumerations.Security.Policy)Enum.Parse(typeof(Enumerations.Security.Policy), policyWrtString), DateTime.UtcNow)));

      /* Note that thisn does not stop you from 
          configuring policies directly against a username, claims, roles, etc. You can do the usual.
     */
            }
        }); 

คลาส DefaultAuthorizationRequirement ดูเหมือนว่า ...

public class DefaultAuthorizationRequirement : IAuthorizationRequirement
{
    public Enumerations.Security.Policy Policy {get; set;} //This is a mere enumeration whose code is not shown.
    public DateTime DateTimeOfSetup {get; set;} //Just in case you have to know when the app started up. And you may want to log out a user if their profile was modified after this date-time, etc.
}

public class DefaultAuthorizationHandler : AuthorizationHandler<DefaultAuthorizationRequirement>
{
    private IAServiceToUse _aServiceToUse;

    public DefaultAuthorizationHandler(
        IAServiceToUse aServiceToUse
        )
    {
        _aServiceToUse = aServiceToUse;
    }

    protected async override Task HandleRequirementAsync(AuthorizationHandlerContext context, DefaultAuthorizationRequirement requirement)
    {
        /*Here, you can quickly check a data source or Web API or etc. 
           to know the latest date-time of the user's profile modification...
        */
        if (_aServiceToUse.GetDateTimeOfLatestUserProfileModication > requirement.DateTimeOfSetup)
        {
            context.Fail(); /*Because any modifications to user information, 
            e.g. if the user used another browser or if by Admin modification, 
            the claims of the user in this session cannot be guaranteed to be reliable.
            */
            return;
        }

        bool shouldSucceed = false; //This should first be false, because context.Succeed(...) has to only be called if the requirement specifically succeeds.

        bool shouldFail = false; /*This should first be false, because context.Fail() 
        doesn't have to be called if there's no security breach.
        */

        // You can do anything.
        await doAnythingAsync();

       /*You can get the user's claims... 
          ALSO, note that if you have a way to priorly map users or users with certain claims 
          to particular policies, add those policies as claims of the user for the sake of ease. 
          BUT policies that require dynamic code (e.g. checking for age range) would have to be 
          coded in the switch-case below to determine stuff.
       */

        var claims = context.User.Claims;

        // You can, of course, get the policy that was hit...
        var policy = requirement.Policy

        //You can use a switch case to determine what policy to deal with here...
        switch (policy)
        {
            case Enumerations.Security.Policy.CanReadResource:
                 /*Do stuff with the claims and change the 
                     value of shouldSucceed and/or shouldFail.
                */
                 break;
            case Enumerations.Security.Policy.AnotherPolicy:
                 /*Do stuff with the claims and change the 
                    value of shouldSucceed and/or shouldFail.
                 */
                 break;
                // Other policies too.

            default:
                 throw new NotImplementedException();
        }

        /* Note that the following conditions are 
            so because failure and success in a requirement handler 
            are not mutually exclusive. They demand certainty.
        */

        if (shouldFail)
        {
            context.Fail(); /*Check the docs on this method to 
            see its implications.
            */
        }                

        if (shouldSucceed)
        {
            context.Succeed(requirement); 
        } 
     }
}

โปรดทราบว่ารหัสข้างต้นยังสามารถเปิดใช้งานการแมปล่วงหน้าของผู้ใช้กับนโยบายในที่เก็บข้อมูลของคุณ ดังนั้นเมื่อเขียนการอ้างสิทธิ์สำหรับผู้ใช้โดยทั่วไปแล้วคุณเรียกคืนนโยบายที่แมปไว้ล่วงหน้ากับผู้ใช้โดยตรงหรือโดยอ้อม (เช่นเนื่องจากผู้ใช้มีค่าการเรียกร้องบางอย่างและมูลค่าการอ้างสิทธิ์นั้นถูกระบุและแมปกับนโยบายเช่น ให้การแมปอัตโนมัติสำหรับผู้ใช้ที่มีค่าการอ้างสิทธิ์ด้วย) และเกณฑ์นโยบายเป็นการเรียกร้องเช่นในตัวจัดการการอนุญาตคุณสามารถตรวจสอบได้ว่าการเรียกร้องของผู้ใช้มีความต้องการนโยบายเป็นค่าของรายการการเรียกร้องใน การเรียกร้อง นั่นเป็นวิธีที่คงที่ในการทำให้เป็นไปตามข้อกำหนดของนโยบายเช่นความต้องการ "ชื่อ" นั้นค่อนข้างคงที่ในธรรมชาติ ดังนั้น,

[Authorize(Policy = nameof(Enumerations.Security.Policy.ViewRecord))] 

ข้อกำหนดแบบไดนามิกอาจเกี่ยวกับการตรวจสอบช่วงอายุ ฯลฯ และนโยบายที่ใช้ข้อกำหนดดังกล่าวไม่สามารถแมปกับผู้ใช้ล่วงหน้าได้

ตัวอย่างของการตรวจสอบการเคลมนโยบายแบบไดนามิก (เช่นเพื่อตรวจสอบว่าผู้ใช้อายุมากกว่า 18 ปี) อยู่ที่คำตอบที่ได้รับจาก @blowdart ( https://stackoverflow.com/a/31465227/4974715 )

PS: ฉันพิมพ์สิ่งนี้ลงในโทรศัพท์ของฉัน ให้อภัยความผิดพลาดใด ๆ และไม่มีการจัดรูปแบบ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.