2016-11-22 41 views
3

我想在自定义属性中进行安全验证。一个很好的例子是,如果用户发出GET请求来检索具有给定ID的实体,我想拦截该属性中的该请求,将其交给操作筛选器,然后确定用户是否有权访问它。我唯一的问题是如何检索实体ID。我无法在属性声明中传递它,因为它会初始化一次而不是每次请求。相反,我想给我的自定义属性一个url模式,就像你会给HttpGet或HttpPost,并根据上下文的url参数来解析,得到一个实体id。解决asp网络核心mvc中的路由段

这里是我的属性:

public class RequireProjectAccessAttribute : TypeFilterAttribute 
{ 
    public string UrlPattern { get; set; } 
    public RequireProjectAccessAttribute(string urlPattern) : base(typeof(RequireProjectAccessFilter)) 
    { 
     UrlPattern = urlPattern; 
     Arguments = new object[] { urlPattern }; 
    } 

    private class RequireProjectAccessFilter : IAsyncActionFilter 
    { 
     private readonly ICurrentSession _currentSession; 
     private readonly string _urlPattern; 

     public RequireProjectAccessFilter(ICurrentSession currentSession, string urlPattern) 
     { 
      _currentSession = currentSession; 
      _urlPattern = urlPattern; 
     } 

     public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) 
     { 
      var projectId = /* some magic to resolve _urlPattern against the current url parameter values */ 
      if (/* user doesn't have access to project */) 
      { 
       context.Result = new UnauthorizedResult(); 
      } 
      else 
      { 
       await next(); 
      } 
     } 
    } 
} 

这里是我怎么想使用它:

[Route("api/[controller]")] 
public class ProjectsController : BaseController 
{ 

    public ProjectsController() 
    { 
    } 

    [RequireProjectAccess("{projectId}")] 
    [HttpGet("{projectId}")] 
    public JsonResult GetById(int projectId) 
    { 
     /* retrieve project */ 
    } 
} 
+0

https://开头channel9.msdn。 com/Blogs/Seth-Juarez/Advanced-aspnet-Core-Authorization-with-Barry-Dorrans |转到此视频并跳过大约30分钟。 –

回答

0

你只需要提供应包含的值,然后使用该路由关键在HttpContext对象上扩展方法GetRouteValue(string key)

var projectId = context.HttpContext.GetRouteValue(_routeKey)?.ToString(); 

这意味着你的属性应该是这样的:

public class RequireProjectAccessAttribute : TypeFilterAttribute 
{ 
    public string RouteKey { get; set; } 
    public RequireProjectAccessAttribute(string routeKey) : base(typeof(RequireProjectAccessFilter)) 
    { 
     RouteKey = routeKey; 
     Arguments = new object[] { routeKey }; 
    } 

    private class RequireProjectAccessFilter : IAsyncActionFilter 
    { 
     private readonly ICurrentSession _currentSession; 
     private readonly string _routeKey; 

     public RequireProjectAccessFilter(ICurrentSession currentSession, string routeKey) 
     { 
      _currentSession = currentSession; 
      _routeKey = routeKey; 
     } 

     public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) 
     { 
      var projectId = context.HttpContext.GetRouteValue(_routeKey)?.ToString(); 
      if (/* user doesn't have access to project */) 
      { 
       context.Result = new UnauthorizedResult(); 
      } 
      else 
      { 
       await next(); 
      } 
     } 
    } 
} 

而且因为这样使用(注意,我传递的路由项的名称):

[RequireProjectAccess("projectId")] 
[HttpGet("{projectId}")] 
public JsonResult GetById(int projectId) 
{ 
    /* retrieve project */ 
} 
+0

这很接近,但我想要解决什么传递到RequireProjectAccess完全相同的方式,HttpGet解析其参数。我不想传递“projectId”,我想传递“{projectId}”并让MVC使用其内部路由解析器使用正确的URL参数解析它。 –

+0

我想我错过了一些东西。由于“{projectId}”已被路由解决,并使RouteData中的projectId参数可用,为什么需要再次解决它? –