2011-12-01 87 views
3

我有一个应用程序,其中一些用户属于一个角色,但实际上可能无法访问URL中的某些数据。例如,下面的网址是开放给所有用户如何显示已验证但未经授权的用户未经授权的页面MVC 3?

/Library/GetFile/1 

然而,一些用户可能无法访问文件1,但我不能使用授权属性来检测。我希望将这些用户重定向到未经授权或访问权限的页面。我使用窗体身份验证和我的配置设置这样

<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错误页面,即使我已经更新了我RegisterGlobalFilters到

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

如果我改变UnauthorizedAccessException到自定义异常重定向作品现在这就是我所做的。

回答

3

你的解决方案是与我相似,除了我这样做:

  1. 创建一个自定义异常,UnauthorizedDataAccessException。

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

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

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

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

请注意,这只是显示一种模式:您如何实现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

最后,这是我做的除了2件事情。我没有创建自定义HandleErrorAttribute,只需在RegisterGlobalFilters方法的第二个HandleError过滤器上设置ExceptionType和Order。我喜欢你的'安全'扩展名的想法!我可能会更多地使用这个想法。 – Steven

+0

@Steven,我打算放弃一个属性,只注册标准的HandleError过滤器,但我注意到你只能指定一个View。由于我正在使用区域,所以我需要明确地说明我的控制器。 –

0

您可以限制对特定角色的访问。如果未经授权的角色尝试访问资源,则可以将其重定向到特定的网址。 看看这个其他的SO问题:attribute-for-net-mvc-controller-action-method,那里有很好的答案。 你可以在你的代码检查,如果用户属于角色:

User.IsInRole("RoleToTest"); 

你也可以属性适用于你的控制器/ action方法。无论如何,它都在我上面指定的链接中解释。

*编辑* 您可以重写基地控制器中的OnException。实现自定义异常,例如AccessNotAuthorizedAccessException。 在OnExcepton中,如果您检测到您的自定义异常,只需重定向到一个友好的网址,显示'Not authorized ...'消息。

+0

我了解如何检查角色并使用授权属性。问题是用户无法访问特定的实体。我不希望将它们重定向到View,我希望能够抛出错误或返回HttpUnauthorizedResult并让MVC处理它。 – Steven

+0

如果您不希望将它们重定向到某个视图,如“您无权查看此内容”,那么您期望的是什么?我会发布一个更新的答案,这将给你一个可能的解决方案,使用自定义的授权属性 – santiagoIT

相关问题