检查用户是否有权访问控制器操作(在访问控制器之前)

时间:2016-12-01 14:08:23

标签: asp.net-core authorization asp.net-core-mvc

我有一个操作TopSecret(),它已应用安全策略:

[Authorize(Policy = "Level2SecurityClearance")]
public IActionResult TopSecret()

我可以通过执行此操作来检查用户是否符合政策要求(authorizationService类型为IAuthorizationService

bool isAuthorised = await authorizationService.AuthorizeAsync(User, "Level2SecurityClearance");

此操作可能会在将来某个时候应用不同的策略,我不希望找到我生成链接的所有位置并更新代码。是否可以测试用户是否可以访问特定操作?

也许是这样的:

// Not a real method!!!
bool isAuthorised = authorizationService.IsAuthorisedForAction(User, "TopSecret", "SecretController");

2 个答案:

答案 0 :(得分:1)

您应该研究开发需求

以下是使用您的标准的示例:

注意:我假设您使用的是Identity3,而您的用户拥有访问权限

在名为Level2SecurityClearanceRequirement

的新类中
public class Level2SecurityClearanceRequirement : AuthorizationHandler<Level2SecurityClearanceRequirement>, IAuthorizationRequirement
{
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, Level2SecurityClearanceRequirement requirement)
    {
        if (context.User.HasClaim("TopSecret","yes")
            context.Succeed(requirement);
        return Task.FromResult(0);
    }
}

在您的控制器方法中:

public async Task<IActionResult> BlahBlah() {
    if (!await _authorizationService.AuthorizeAsync(User, nameof(PolicyName.Level2SecurityClearance), new Level2SecurityClearanceRequirement()))
        return new ChallengeResult();
}

请注意,我在这里使用了nameof(),因此您没有任何魔术字符串,并且所有资源都是集中的。

在这种情况下,我有一个枚举:

public enum PolicyName {
    Level2SecurityClearance
}

在您的startup.cs中:

在ConfigureServices方法中

添加以下内容:

services.AddAuthorization(options =>{
    options.AddPolicy(nameof(PolicyName.Level2SecurityClearance), policy => { policy.AddRequirements(new Level2SecurityClearanceRequirement()); });
});

然后您可以随意使用此要求,并在要求本身中完成检查

答案 1 :(得分:0)

试试这个。在 ASP.NET Core 1.1

中测试
//somewhere in view
@if (await Url.HasAccess(urlActionContext))
{
    <p>You have access</p>
}

扩展方法

public static async Task<bool> HasAccess(this IUrlHelper urlHelper, UrlActionContext urlActionContext, string httpMethod = "GET" )
{

    var httpContext = urlHelper.ActionContext.HttpContext;

    var routeValues = new RouteValueDictionary(urlActionContext.Values);
    routeValues["action"] = urlActionContext.Action;
    routeValues["controller"] = urlActionContext.Controller;          

    var path = urlHelper.Action(urlActionContext);

    var features = new FeatureCollection();
    features.Set<IHttpRequestFeature>(new HttpRequestFeature()
    {
        Method = httpMethod, 
        Path = path,

    });

    var ctx = new DefaultHttpContext(features);      

    var routeContext = new RouteContext(ctx);

    foreach (var entry in routeValues)
    {
        routeContext.RouteData.Values.Add(entry.Key, entry.Value);
    }

    var actionSelector = httpContext.RequestServices.GetRequiredService<IActionSelector>();

    var provider = httpContext.RequestServices.GetRequiredService<IActionDescriptorCollectionProvider>();       
    var actionDescriptors = actionSelector.SelectCandidates(routeContext);

    var actionDescriptor = actionSelector.SelectBestCandidate(routeContext, actionDescriptors);

    var authService = httpContext.RequestServices.GetRequiredService<IAuthorizationService>();

    //You need to implement your own AuthorizationHandler that 
    //checks the actionDescriptor. It will be in AuthorizationHandlerContext.Resource. 
    //In my case, I have custom Authorize attribute applied to the 
    //controller action and this attribute is available 
    //in actionDescriptor.FilterDescriptors

    var ok = await authService.AuthorizeAsync(httpContext.User, actionDescriptor, "YOUR_POLICY"); 

    return ok;

}