我试图使一个自定义授权属性在ASP。净的核心。在以前的版本中,可以重写bool AuthorizeCore(HttpContextBase httpContext)。但是这在AuthorizeAttribute中不再存在。

当前制作自定义AuthorizeAttribute的方法是什么?

我想要完成的:我正在头授权中接收会话ID。通过该ID,我将知道特定操作是否有效。


当前回答

下面是一个简单的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
{
}

其他回答

当前制作自定义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() { ... }
}

对于身份验证,最好在中间件级别进行处理。

你到底想达到什么目的?

在写这篇文章时,我相信这可以用asp.net core 2及以上的iclaimstrtransform接口来完成。我刚刚实现了一个概念的证明,可以分享到这里。

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;
    }
}

要在你的控制器中使用它,只需在你的方法中添加适当的[授权(角色="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的授权标头。这是原型,我相信下周我们会在我们的生产系统中做一些非常接近的东西。

未来的选民,在投票时,请考虑投票日期。到今天为止,这在我的机器上还能用。您可能需要在实现上进行更多的错误处理和日志记录。

下面的代码适合我在。net Core 5中使用

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class AccessAuthorizationAttribute : AuthorizeAttribute, IAuthorizationFilter
{
    public string Module { get; set; } //Permission string to get from controller

    public AccessAuthorizationAttribute(string module)
    {
        Module = module;
    }
    public void OnAuthorization(AuthorizationFilterContext context)
    {
        //Validate if any permissions are passed when using attribute at controller or action level

        if (string.IsNullOrEmpty(Module))
        {
            //Validation cannot take place without any permissions so returning unauthorized
            context.Result = new UnauthorizedResult();
            return;
        }
       
        if (hasAccess)
        {
            return;
        }

        context.Result = new UnauthorizedResult();
        return;
    }
}

这里很多人已经说过了,但是有了策略处理程序,你就可以在。net框架中使用旧方法实现的功能而言,你可以走得更远。

我在SO网站上快速写了一个答案:https://stackoverflow.com/a/61963465/7081176 对我来说,在制作了一些类后,它完美地工作了:

EditUserRequirement:

public class EditUserRequirement : IAuthorizationRequirement
{
    public EditUserRequirement()
    {
    }
}

一个抽象处理程序,使我的生活更容易:

public abstract class AbstractRequirementHandler<T> : IAuthorizationHandler
    where T : IAuthorizationRequirement
{
    public async Task HandleAsync(AuthorizationHandlerContext context)
    {
        var pendingRequirements = context.PendingRequirements.ToList();
        foreach (var requirement in pendingRequirements)
        {
            if (requirement is T typedRequirement)
            {
                await HandleRequirementAsync(context, typedRequirement);
            }
        }
    }

    protected abstract Task HandleRequirementAsync(AuthorizationHandlerContext context, T requirement);
}

抽象处理程序的实现:

public class EditUserRequirementHandler : AbstractRequirementHandler<EditUserRequirement>
{
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, EditUserRequirement requirement)
    {
        // If the user is owner of the resource, allow it.
        if (IsOwner(context.User, g))
        {
            context.Succeed(requirement);
        }

        return Task.CompletedTask;
    }

    private static bool IsOwner(ClaimsPrincipal user, Guid userIdentifier)
    {
        return user.GetUserIdentifier() == userIdentifier;
    }
}

注册我的处理程序和需求: 服务。AddSingleton < IAuthorizationHandler, EditUserRequirementHandler > ();

        services.AddAuthorization(options =>
        {
            options.AddPolicy(Policies.Policies.EditUser, policy =>
            {
                policy.Requirements.Add(new EditUserRequirement());
            });
        });

然后使用我在Blazor的策略:

<AuthorizeView Policy="@Policies.EditUser" Resource="@id">
    <NotAuthorized>
        <Unauthorized />
    </NotAuthorized>
    <Authorized Context="Auth">
        ...
    </Authorized>
</AuthorizeView>

我希望这对面临这个问题的人有用。

什么? !

我决定再补充一个简单的答案。B/c我发现大多数答案都有点过度设计。也因为我需要一种授予授权的方法,而不仅仅是否认它。这里的大多数答案都提供了一种“加强”安全性的方法,但我想“放松”它。例如:“如果配置了某些应用程序设置,则允许匿名用户访问”。

public class MyAuthAttribute : Attribute, IAuthorizationFilter
{
    public void OnAuthorization(AuthorizationFilterContext context)
    {
        //check access 
        if (CheckPermissions())
        {
            //all good, add optional code if you want. Or don't
        }
        else
        {
            //DENIED!
            //return "ChallengeResult" to redirect to login page (for example)
            context.Result = new ChallengeResult(CookieAuthenticationDefaults.AuthenticationScheme);
        }
    }
}

就是这样。不需要混淆“策略”,“声明”,“处理程序”和其他[哔]

用法:

// GET api/Get/5
[MyAuth]
public ActionResult<string> Get(int id)
{
    return "blahblah";
}