Создание атрибута AuthorizeAttribute - что мне нужно знать? - PullRequest
13 голосов
/ 12 января 2012

Вот мои требования:

  • Я буду добавлять пользователей к N количеству ролей;определено в базе данных.

  • Мне нужно защитить каждое действие контроллера с помощью моего атрибута авторизации.

Например, веб-приложение проверит, принадлежит ли зарегистрированный пользовательк любой из этих двух ролей, и если они это сделают, я позволю им войти. Как я могу указать атрибуту Authorize выбирать роли пользователей из выбранной таблицы базы данных?

 [Authorize(Roles = "Admin, Technician")]
 public ActionResult Edit(int id)
 {
     return View();
 }

Я пробовал поискать в Google на многих страницах, но ни одна из них не подходит для того, что мне нужно, и слишком сложна.

Если в официальной документации есть что-то, что я хотел бы найтиа также, поскольку я не видел ничего, что я мог бы использовать.

Есть предложения?

Например, у этого вопроса очень четкий ответ, но я не знаю, завершен ли онили отсутствует что-то важное.

ASP.NET MVC3 Управление ролями и разрешениями -> С назначением разрешений во время выполнения


Редактировать

Кажется, что я на самом деле ищусоздание собственного поставщика ролей, правильно?Нужно ли для реализации этого класса и использования его в качестве моего поставщика ролей?Я новичок в этом, есть мысли?

http://msdn.microsoft.com/en-us/library/8fw7xh74.aspx

Ответы [ 3 ]

10 голосов
/ 05 июня 2012

Последние пару недель я проходил по тому же сценарию, так что это может помочь кому-то еще в той же лодке.Мой сценарий - приложение MVC4 в корпоративной сети с пользователями, хранящимися в Active Directory.Это позволяет для аутентификации Windows давать единый вход в систему, поэтому не требуется аутентификация с помощью форм.Роли хранятся в базе данных Oracle.У меня есть 3 роли:

  • Только для чтения: все пользователи должны быть участником этой группы, чтобы получить доступ к приложению
  • Пользователь: Создать новые записи
  • Администратор: Редактировать иудалить записи

Я решил использовать API поставщика роли asp.net для создания собственного AccountRoleProvider.Пока что мне нужно использовать только 2 метода: GetRolesForUser и IsUserInRole:

public class AccountRoleProvider : RoleProvider // System.Web.Security.RoleProvider
{
    private readonly IAccountRepository _accountRepository;

    public AccountRoleProvider(IAccountRepository accountRepository)
    {
        this._accountRepository = accountRepository;
    }

    public AccountRoleProvider() : this (new AccountRepository())
    {}

    public override string[] GetRolesForUser(string user521)
    {
        var userRoles = this._accountRepository.GetRoles(user521).ToArray();

        return userRoles;
    }

    public override bool IsUserInRole(string username, string roleName)
    {
        var userRoles = this.GetRolesForUser(username);

        return Utils.IndexOfString(userRoles, roleName) >= 0;
    }
}

Я обновил web.config, чтобы использовать моего поставщика ролей:

<authentication mode="Windows" />
<roleManager enabled="true" defaultProvider="AccountRoleProvider">
  <providers>
    <clear/>
    <add name="AccountRoleProvider"
         type="MyApp.Infrastructure.AccountRoleProvider" />
  </providers>
</roleManager>

Затем я создал 2настраиваемые атрибуты из AuthorizeAttribute, ReadOnlyAuthorize и CustomAuthorize.

ReadonlyAuthorize:

public class ReadonlyAuthorize : AuthorizeAttribute
{
    private IAccountRepository _accountRepository;

    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        var user = httpContext.User;
        this._accountRepository = new AccountRepository();

        if (!user.Identity.IsAuthenticated)
        {
            return false;
        }

        // Get roles for current user
        var roles = this._accountRepository.GetRoles(user.Identity.Name);

        if (!roles.Contains("readonly"))
        {
            return false;
        }

        return base.AuthorizeCore(httpContext);
    }

    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        base.OnAuthorization(filterContext);

        if (filterContext.HttpContext.User.Identity.IsAuthenticated && filterContext.Result is HttpUnauthorizedResult)
        {
            filterContext.Result = new ViewResult { ViewName = "AccessDenied" };
        }
    }
}

CustomAuthorize:

public class CustomAuthorizeAttribute : AuthorizeAttribute
{
    public string RedirectActionName { get; set; }
    public string RedirectControllerName { get; set; }
    private IAccountRepository _accountRepository;

    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        var user = httpContext.User;
        this._accountRepository = new AccountRepository();
        var accessAllowed = false;

        // Get the roles passed in with the (Roles = "...") on the attribute
        var allowedRoles = this.Roles.Split(',');

        if (!user.Identity.IsAuthenticated)
        {
            return false;
        }

        // Get roles for current user
        var roles = this._accountRepository.GetRoles(user.Identity.Name);

        foreach (var allowedRole in allowedRoles)
        {
            if (roles.Contains(allowedRole))
            {
                accessAllowed = true;
            }
        }

        if (!accessAllowed)
        {
            return false;
        }

        return base.AuthorizeCore(httpContext);
    }

    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        base.OnAuthorization(filterContext);

        if (filterContext.HttpContext.User.Identity.IsAuthenticated && filterContext.Result is HttpUnauthorizedResult)
        {   
            var values = new RouteValueDictionary(new
            {
                action = this.RedirectActionName == string.Empty ? "AccessDenied" : this.RedirectActionName,
                controller = this.RedirectControllerName == string.Empty ? "Home" : this.RedirectControllerName
            });

            filterContext.Result = new RedirectToRouteResult(values);
        }
    }
}

Причина 2 разных атрибутов заключается в том, что я использую один для роли Readonly, что все пользователи должны быть участникамидля того, чтобы получить доступ к приложению.Я могу добавить это в метод RegisterGlobalFilters в Global.asax, что означает, что он применяется автоматически к каждому контроллеру:

public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
    filters.Add(new HandleErrorAttribute());
    filters.Add(new ReadonlyAuthorize());
}

Затем в CustomAuthorize я могу использовать более детальный подход и указать роли, которые я хочу и применить.к контроллеру или отдельному действию, например ниже, я могу ограничить доступ к методу удаления для пользователей в роли администратора:

[AccessDeniedAuthorize(RedirectActionName = "AccessDenied", RedirectControllerName = "Home", Roles = "Admin")]
public ActionResult Delete(int id = 0)
{
    var batch = myDBContext.Batches.Find(id);
    if (batch == null)
    {
        return HttpNotFound();
    }

    return View(batch);
}

Существуют дополнительные шаги, которые мне нужно предпринять, такие как обновление объекта User ролямитекущий пользователь является членом.Это будет извлекать роли для пользователя один раз, а не каждый раз в моих пользовательских атрибутах, а также использовать User.IsInRole.Нечто подобное должно быть возможно в Application_AuthenticateRequest в Gloal.asax:

var roles = "get roles for this user from respository";

if (Context.User != null)
    Context.User = new GenericPrincipal(Context.User.Identity, roles);
1 голос
/ 12 января 2012

Существует множество способов справиться с этим. Метод Дарина и Бодрартс (оба очень опытные люди - один из них также является автором по безопасности) хороши в приведенной вами ссылке.

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

Фильтры OutputCache и Authorize в MVC3

и

Почему я не могу объединить атрибуты [Authorize] и [OutputCache] при использовании кэша Azure (приложение .NET MVC3)?

и

Реализация пользовательской аутентификации, авторизации и ролей MVC

для получения дополнительной информации об этом и о том, как обрабатывать кэширование, если вы используете атрибут авторизации.

0 голосов
/ 12 января 2012

Вы можете использовать поставщика членства по умолчанию и поставщика ролей вместо того, чтобы реализовывать свой собственный, но вам также потребуется использовать базу данных членства asp.net по умолчанию, aspnetdb.mdf.

См. здесь для прохождения

...