2016-08-15 1 views
0

Можно ли использовать пользовательские фильтры в режиме бритвы?Возможно ли использовать пользовательские фильтры на основе AuthorizeAttribute в представлении Razor?

К примеру, у меня есть это работает в контроллере:

[Privilege(Privileges ="AdminRead, AdminWrite"))] 
public ActionResult Index() 
{ 
return View(); 
} 

Но есть возможность сделать что-то вроде следующего в Бритва cshtml файле:

if(@[Privilege(Privileges ="AdminRead, AdminWrite"))]) 
{ 
//html goes here 
} 

Если это делает разница, атрибут PrivilegeAttribute происходит от AuthorizeAttribute.

PrivilegeAttribute.cs

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Security.Claims; 
using System.Web; 
using System.Web.Mvc; 
using System.Web.Security; 

namespace IdentityDevelopment.Infrastructure 
{ 
    [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true, AllowMultiple = true)] 
    public class PrivilegeAttribute : AuthorizeAttribute 
    { 
     private static readonly string[] _emptyArray = new string[0]; 


     private string _privileges; 
     private string[] _privilegesSplit = _emptyArray; 

     public string Privileges 
     { 
      get { return _privileges ?? String.Empty; } 
      set 
      { 
       _privileges = value; 
       _privilegesSplit = SplitString(value); 
      } 
     } 

     internal static string[] SplitString(string original) 
     { 
      if (String.IsNullOrEmpty(original)) 
      { 
       return _emptyArray; 
      } 

      var split = from piece in original.Split(',') 
         let trimmed = piece.Trim() 
         where !String.IsNullOrEmpty(trimmed) 
         select trimmed; 
      return split.ToArray(); 
     } 

     public PrivilegeAttribute(string privilegeList) 
    { 
     _privileges = privilegeList; 
    } 
     protected override bool AuthorizeCore(HttpContextBase httpContext) 
     { 
      bool isAuthorized = base.AuthorizeCore(httpContext); 

      if (isAuthorized) { 
       string[] rolesArray; 

       var roles = ((ClaimsIdentity)httpContext.User.Identity).Claims 
        .Where(c => c.Type == ClaimTypes.Role) 
        .Select(c => c.Value); 

       rolesArray = roles.ToArray(); 

       //Assume that a user can only be associated to 0 or 1 role. If 0 the rolesArray will be null. 

       if (rolesArray != null) 
       { 
        string roleUser = rolesArray[0]; 

        SQLRolerecord CheckPrivInRole = new SQLRolerecord(); 

        return CheckPrivInRole.Allow(roleUser, _privilegesSplit); 

       } 
       else 
       { 
        return false; 
       } 
      } 
      else 
      { 
       return false; 
      } 


     } 

    } 
} 

Спасибо.

+1

Это невозможно? '@if (User.IsInRole (« WhateverUserRole »))' – techspider

+0

или '@if (User.IsAuthorized)' должен делать это – jbutler483

+0

@techspider Да, я использовал это и возможно, но как насчет пользовательских атрибутов AuthorizeAttributes? Например, у меня есть один, называемый PrivilegeAttribute, который принимает вход, называемый «Привилегии», так как же я мог бы сделать подобное? Как создать метод с именем IsInPrivilege? – ITWorker

ответ

1

Я считаю, что ответ на ваш вопрос инкапсулирован довольно хорошо here.

Вы можете ограничить доступ пользователя на основе безопасности на основе роли.

@if (User.IsInRole("Admin")) 
{ 
    //here blocks that you want to show to users with Admin role 
} 

Вы также можете обрабатывать авторизацию через контроллер, такой как.

public ActionResult Index() 
{ 
    if(User.IsInRole("Admin")) 
    { 
     return View("Admin"); 
    } 
    return View("User"); 
} 

Однако вы специально хотите атрибут Authorize, такой как.

[Authorize(Roles = "Admin")] 
public ActionResult SaveTopSecret() 
{ 

} 
+0

Я думаю, что вы, возможно, написали этот ответ во время редактирования. Я знаю, как это сделать с помощью User.IsInRole, но я хотел знать, можно ли это сделать с помощью специального типа авторизации, и это то, что я редактировал в моем исходном вопросе. – ITWorker

1

Добавление атрибутов или фильтров в представления не является предпочтительным. Вы можете взять добычу на this MSDN article.

Фильтры могут применяться при действии, контроллере или уровне приложения.

Вы также можете получить то же самое, проверив User.IsInRole в вашем представлении и выполнив необходимые операции.

В качестве альтернативы вы также можете реализовать пользовательские HTML-помощники, которые могут действовать как методы расширения по вашим элементам управления HTML. Вы можете проверить пример в вопросе here.

1

Теоретически, поскольку ViewContext расширяет ControllerContext, вы можете создать экземпляр атрибута и ссылаться на него, как это:

@if(new PrivilegeAttribute{Privileges = "AdminRead, AdminWrite"} 
     .AuthorizeCore(new AuthorizationContext(this.ViewContext))) 
{ 
    ... 
} 

Это не то же самое «добавив атрибут» к представлению, но она позволяет повторно использовать пользовательскую логику атрибута из вашего представления, чтобы избежать повторения кода.

Однако, следует отметить, что предпочтительным способ сделать то, что вы делаете это:

  1. поставить логику в отдельный класс
  2. инъекционные этого класса (или его интерфейс) в ваш контроллер
  3. разрешить действие контроллера вызвать этот метод класса/интерфейса, чтобы узнать, имеет ли пользователь привилегии.
  4. имеют действие контроллера, сохраняют эту информацию на сильно типизированной модели представления и передают модель представления в вид
  5. имеют вид, доступ к свойству вида-модели, чтобы определить, как отображать вещи.
+0

Интересное предложение !! Вы пробовали это? Можно ли сделать его эквивалентным '[Privilege (Privileges =" AdminRead, AdminWrite "))]'? – techspider

+0

@techspider: Я сам не пробовал, но я не могу придумать, почему он не должен работать. См. Мой обновленный ответ о том, как сделать его эквивалентным тому, что вы опубликовали. – StriplingWarrior

+0

Я рассмотрю предпочтительный метод, который вы опубликовали, однако, когда я попытался с помощью подхода, который вы предложили с кодом Razor, я вижу сообщение об ошибке «Тип или имя пространства имен» PrivilegeAttribute не удалось найти (вам не хватает директивы using или ссылку на сборку?) 'В настоящее время мой взгляд не сильно типизирован для какой-либо модели. – ITWorker

1

Хорошо, я спустил маршрут AuthorizeAttribute для использования перечислений для установки разрешений. Это показалось немного более ясным и немного меньше использующих строк для определения разрешений.

Так что это отлично работает в контроллере

[AccessRole(AccessLevel.SuperAdmin, AccessLevel.Admin)] 

, например. Теперь нам нужно заняться бритвой. Шаг 1 добавить это в классе AccessRole

public bool Auth(HttpContextBase httpContext) 
     { 
      return this.AuthorizeCore(httpContext); 
     } 

Шаг 2 добавить этот класс (уровень доступа является перечисление)

public static class AccessRoleHelper { 


     public static bool IsInRole(HttpContextBase httpContext, params AccessLevel[] roles) 
    { 

     var ac = new AccessRole(roles); 

     return ac.Auth(httpContext); 

    } 



    } 

Шаг 3. Добавьте пространство имен в бритве web.cong

Этап 4.

@if (AccessRoleHelper.IsInRole(this.Context, AccessLevel.Admin, AccessLevel.SuperAdmin)) 
    <p>has access</p> 
} 

Ммм, я все еще учась C# - но, как всегда, я прошу myse Если я доволен этим решением? Время покажет. Но решение не менее.

[Редактировать] Вы можете немного очистить, добавив в зону бритвы пространство имен.

+0

К тому времени, как я прочитал ваш ответ, я закончил реализацию этой версии.Спасибо, что ответили. – ITWorker

1

Attribute является ...

Выдержки:

мощный метод связывания метаданных или декларативной информации, с кодом (узлов, типов, методов, свойств и т.д.). После того, как атрибут связан с программным сущностью, атрибут может быть запрошен во время выполнения с использованием метода, называемого отражением.

Так что ваш код:

if(@[Privilege(Privileges ="AdminRead, AdminWrite"))]) 
{ 
    //html goes here 
} 

полностью недействительным, как атрибуты могут быть связаны только с типами, метод или свойств. (aka ...)

[MyClassAttribute] 
public class MyClass 
{ 
    [MyPropertyAttribute] 
    public int Height { get; set; } 

    [MyMethodAttribute] 
    public int GetWidth() 
    { 
    //..... 
    } 
} 

Похоже, вы хотите инкапсулировать и повторно использовать свой код. Если это так, вам нужно удалить большую часть кода в свой пользовательский атрибут и поместить его в другое место.Например, вы могли бы:

public static class IPrincipleExtensions 
{ 
    public static bool HasAccess(this IPrinciple principle, IEnumerable<string> roles) 
    { 
    } 
} 

Этот атрибут для контроллеров

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, 
Inherited = true, 
AllowMultiple = true)] 
public class PrivilegeAttribute : AuthorizeAttribute 
{ 
    protected override bool AuthorizeCore(HttpContextBase httpContext) 
    { 
    bool isAuthorized = base.AuthorizeCore(httpContext); 

    if (isAuthorized) 
    { 
     httpContext.Identity.HasAccess(_privilegesSplit) 
    } 

    return isAuthorized; 
} 

И вы могли бы повторно использовать PrivilegeProvider в представлении

// something like 
@if(User.HasAccess("AdminRead, AdminWrite")) 
{ 
    //html goes here 
} 

Хотя использовать его таким образом, это просто хак вокруг User.IsInRole действительно так больше кода, чтобы сделать то же самое.

+0

Спасибо за объяснение. – ITWorker

Смежные вопросы