【问题标题】:How can I show Authenticated but UNAUTHORIZED users an unauthorized page MVC 3?如何向经过身份验证但未经授权的用户显示未经授权的页面 MVC 3?
【发布时间】:2011-12-01 21:54:16
【问题描述】:

我有一个应用程序,其中一些用户属于某个角色,但实际上可能无法访问 URL 中的某些数据。例如以下网址对所有用户开放

/Library/GetFile/1

但是,有些用户可能无法访问 file1,但我无法使用 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,表单身份验证正在劫持该代码并将用户发送到登录页面。

即使我已将 RegisterGlobalFilters 更新为

,抛出 UnauthorizedAccessException 似乎也无法始终将用户重定向到 IIS 错误页面
filters.Add(new HandleErrorAttribute
{
    ExceptionType = typeof(UnauthorizedAccessException),
    View = "Unauthorized",
    Order = 3
});

如果我将 UnauthorizedAccessException 更改为自定义 Exception,则重定向会起作用,现在这就是我所做的。

【问题讨论】:

    标签: asp.net-mvc-3 iis-7 forms-authentication unauthorized


    【解决方案1】:

    除了我这样做之外,您的解决方案与我的类似:

    1. 创建自定义异常 UnauthorizedDataAccessException。

    2. 创建自定义异常过滤器(以便它可以记录无效的访问尝试)。

    3. 将我的自定义异常属性注册为 App_start 中的全局过滤器。

    4. 创建一个标记接口 ISecureOwner 并将其添加到我的实体中。

    5. 向我的存储库添加一个安全的“加载”扩展方法,如果当前用户不是已加载实体的所有者,则会引发异常。为此,实体必须实现返回保存实体的用户 ID 的 ISecureOwner。

    请注意,这只是显示了一种模式:您如何实现 GetSecureUser 以及您使用什么来检索数据的细节会有所不同。然而,虽然这种模式对于小型应用程序来说是可以的,但它有点 hack,因为这种安全性应该在数据级别深入实施,使用数据库中的所有权组,这是另一个问题 :)

        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))
    

    【讨论】:

    • 最后这就是我所做的,除了两件事。我没有创建自定义 HandleErrorAttribute,只是在我的 RegisterGlobalFilters 方法中的第二个 HandleError 过滤器上设置了 ExceptionType 和 Order。我喜欢你的存储库上的“安全”扩展的想法!我可能会再考虑一下这个想法。
    • @Steven,我打算放弃一个属性,只注册标准的 HandleError 过滤器,但我注意到你只能指定一个视图。由于我使用的是区域,因此我需要明确说明我的控制器。
    【解决方案2】:

    您可以限制对某些角色的访问。如果未经授权的角色尝试访问资源,您可以将它们重定向到特定的 url。 看看另一个 SO 问题:attribute-for-net-mvc-controller-action-method,那里有很好的答案。 如果用户属于某个角色,您可以签入您的代码:

    User.IsInRole("RoleToTest");
    

    您还可以将属性应用于您的控制器/操作方法。无论如何,这一切都在我上面指定的链接中进行了解释。

    * 编辑 * 您可以在基本控制器中覆盖 OnException。实现自定义异常,例如 AccessNotAuthorizedAccessException。 在 OnExcepton 中,如果您检测到自定义异常,只需重定向到显示“未授权...”消息的友好 url。

    【讨论】:

    • 我了解如何检查角色并使用授权属性。问题是用户无权访问特定实体。我不想将它们重定向到视图,我希望能够抛出错误或返回 HttpUnauthorizedResult 并让 MVC 处理它。
    • 如果您不希望将他们重定向到显示“您无权查看此内容”之类的视图,您期望的是什么?我将发布一个更新的答案,这将为您提供使用自定义授权属性的可能解决方案
    猜你喜欢
    • 2018-06-13
    • 2021-07-17
    • 2018-07-09
    • 2018-10-16
    • 2016-08-15
    • 1970-01-01
    • 1970-01-01
    • 2015-09-28
    相关资源
    最近更新 更多