Как я могу показать Аутентифицированным, но НЕЗАКОННЫМ пользователям неавторизованную страницу MVC 3? - PullRequest
3 голосов
/ 02 декабря 2011

У меня есть приложение, в котором некоторые пользователи принадлежат к роли, но на самом деле могут не иметь доступа к определенным данным в URL. Например, следующий URL открыт для всех пользователей

/Library/GetFile/1

Однако некоторые пользователи могут не иметь доступа к файлу1, но я не могу использовать атрибут Authorize, чтобы обнаружить это. Вместо этого я хочу перенаправить этих пользователей на неавторизованную или закрытую страницу. Я использую проверку подлинности с помощью форм, и моя конфигурация настроена следующим образом

<authentication mode="Forms">
    <forms loginUrl="~/Home/Index" timeout="2880" />
</authentication>

мой блок пользовательских ошибок похож на

<customErrors mode="On" defaultRedirect="Error" redirectMode="ResponseRewrite" >
    <error statusCode="401" redirect="Unauthorized"/>
</customErrors>

Я пытаюсь вернуть HttpUnauthorizedResult, если у пользователя нет доступа, но я просто перенаправлен на страницу входа, которая здесь недопустима, поскольку пользователь уже аутентифицирован.


Похоже, что HttpUnauthorizedResult устанавливает для HTTP-кода ответа 401, который используется для проверки подлинности с помощью форм и отправки пользователя на страницу входа в систему.

Бросок UnauthorizedAccessException, кажется, не работает или всегда перенаправляет пользователя на страницу IIS Error, хотя я обновил мои RegisterGlobalFilters до

filters.Add(new HandleErrorAttribute
{
    ExceptionType = typeof(UnauthorizedAccessException),
    View = "Unauthorized",
    Order = 3
});

Если я заменил UnauthorizedAccessException на пользовательское исключение, перенаправление сработает, и на данный момент это то, что я сделал.

Ответы [ 2 ]

3 голосов
/ 02 декабря 2011

Ваше решение аналогично моему, за исключением того, что я сделал это:

  1. Создание настраиваемого исключения, UnauthorizedDataAccessException.

  2. Создание настраиваемого исключенияфильтр (чтобы он мог регистрировать недопустимую попытку доступа).

  3. Зарегистрируйте мой атрибут пользовательского исключения в качестве глобального фильтра в App_start.

  4. Создайте интерфейс маркера ISecureOwner и добавьте его в мою сущность.

  5. Добавить безопасный метод расширения «Загрузка» в мой репозиторий, который выдает исключение, если текущий пользователь не является владельцем объекта, который был загружен.Чтобы это работало, сущность должна реализовать ISecureOwner, который возвращает идентификатор пользователя, который сохранил сущность.

Обратите внимание, что это просто показывает шаблон: подробности того, как вы реализуете GetSecureUser ито, что вы используете для извлечения данных, будет различным.Тем не менее, хотя этот шаблон подходит для небольшого приложения, он немного хакерский, поскольку этот тип безопасности должен быть реализован глубоко на уровне данных с использованием групп владения в базе данных, что является другим вопросом:)

    public class UnauthorizedDataAccessException : Exception
    {
        // constructors
    }

    public class UnauthorizedDataAccessAttribute : HandleErrorAttribute
    {
        public override void OnException(ExceptionContext filterContext)
        {
            if (filterContext.Exception.GetType() == Typeof(UnauthorizedDataAccessException))
            {
                // log error
                filterContext.ExceptionHandled = true;
                filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary(new { controller = "Error", action = "UnauthorizedDataAccess" }));
            }
            else
            {
                base.OnException(filterContext);
            }
        }

    // marker interface for entity and extension method    
    public interface ISecureOwner
    {
        Guid OwnerId { get; }
    }

    // extension method
    public static T SecureFindOne<T>(this IRepository repository, Guid id) where T : class, ISecureOwner, new()
    {
        var user = GetSecureUser();
        T entity = repository.FindOne<T>(id);

        if (entity.OwnerId != user.GuidDatabaseId)
        {
            throw new UnauthorizedDataAccessException(string.Format("User id '{0}' attempted to access entity type {1}, id {2} but was not the owner. The real owner id is {3}.", user.GuidDatabaseId, typeof(T).Name, id, entity.OwnerId));
        }

        return entity;
    }

    // Register in global.asax
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        var filter = new UnauthorizedDataAccessAttribute { ExceptionType = typeof(UnauthorizedDataAccessException) };
        filters.Add(filter);
        filters.Add(new HandleErrorAttribute());
    }

   // Usage:
   var ownedThing = myRepository.SecureFindOne<myEntity>(id))
0 голосов
/ 02 декабря 2011

Вы можете ограничить доступ к определенным ролям.Если неавторизованная роль пытается получить доступ к ресурсу, вы можете перенаправить их на определенный URL-адрес.Посмотрите на этот другой вопрос SO: attribute-for-net-mvc-controller-action-method , там есть хорошие ответы.Вы можете проверить в своем коде, принадлежит ли пользователь роли:

User.IsInRole("RoleToTest");

, вы также можете применить атрибуты к вашим контроллерам / методам действий.В любом случае все это объясняется по ссылке, указанной мной выше.

* EDIT * Вы можете переопределить OnException в вашем базовом контроллере.Реализуйте пользовательское исключение, например AccessNotAuthorizedAccessException.В OnExcepton, если вы обнаружите свое пользовательское исключение, просто перенаправьте на понятный URL-адрес, который отображает сообщение «Не авторизовано ...».

...