3

我有一个应用程序,其中一些用户属于某个角色,但实际上可能无法访问 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 更新为

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

如果我将 UnauthorizedAccessException 更改为自定义异常,则重定向有效,现在这就是我所做的。

4

2 回答 2

3

您的解决方案与我的类似,只是我这样做了:

  1. 创建自定义异常 UnauthorizedDataAccessException。

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

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

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

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

请注意,这只是显示了一种模式:您如何实现 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))
于 2011-12-02T18:16:49.883 回答
0

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

User.IsInRole("RoleToTest");

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

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

于 2011-12-01T22:39:34.543 回答