1

这是我使用表单身份验证的 MVC 4 Internet 项目的问题。假设我有酒店,我希望授权用户以不同的角色访问每个酒店。

所以用户登录。然后从下拉列表中选择目标酒店,应用程序的安全性相应地做出响应。

我需要 [Authorize(Roles = "Administrator")] 之类的东西,但仅限于该酒店范围内。

我的第一个方法是从 AuthorizeAttribute 继承并覆盖 AuthorizeCore 就像在这个 线程中显示的那样

从那里我可以获得 HttpContext.Session["HotelId"] 并查询 UserRolesInHotel 表。也就是说,我应该有自己的角色表,其结构类似于 UserId、RoleId、HotelId。所以 SimpleRolePrivider 无法完成这项任务,我将被迫创建一个 CustomerRoleProvider。RoleProvider 方法在向用户添加新角色时不会处理我需要的额外参数,例如 HotelId。

为了澄清:

  1. 用户 A 使用用户/密码登录 -> OK (SimpleMembershipProvider)
  2. 经过身份验证的用户 A 选择酒店 1 -> 用户 A 是酒店 1 的“管理员”。
  3. 经过身份验证的用户 A 更改为酒店 2 -> 用户 A 是酒店 2 中的“用户”

我可以拥有任意数量的酒店。

  1. 用户 A -> 酒店 1 -> {“管理员”,“用户”}
  2. 用户 A -> 酒店 2 -> {“用户”}
  3. 用户 A -> 酒店 3 -> {“所有者”}
  4. 用户 A -> 酒店 4 -> {“管理员”}

角色列表始终相同。

几天来我一直在努力解决这个问题,但我想不出一个实用的解决方案。任何想法将不胜感激。

谢谢!

4

1 回答 1

0

这就是我所做的:

  • 向用户配置文件添加了 DefaultBuildingId。
  • 然后我创建了一个 CustomRoleProvider 并像这样覆盖了 GetRolesForUser 方法

    public override string[] GetRolesForUser(string userName)
    {
        if (HttpContext.Current.Session != null)
        {
            var user = _userRepository.GetByName(userName);
    
            if (!user.IsActive)
            {
                throw new ApplicationException(string.Format("some message {0}", userName));
            }
    
            if (HttpContext.Current.Session["BuildingId"] == null)
            {
                var building = _buildingRepository.Get(user.DefaultBuildingId);
                if (building == null)
                {
                    throw new ApplicationException("error message");
                }
    
                HttpContext.Current.Session["BuildingId"] = building.BuildingId;
            }
    
            int buildingId = Convert.ToInt32(HttpContext.Current.Session["BuildingId"]);
            return _userRepository.GetRolesForUserInBuilding(user.UserId, buildingId).ToArray();
        }
    
        throw new ApplicationException("error message.");
    }
    
    • 添加了自定义 AuthorizeAttribute

      protected override bool AuthorizeCore(HttpContextBase httpContext)
      {
      var authorized = base.AuthorizeCore(httpContext);
      if (!authorized)
      {
          return false;
      }
      
      var repo = UnityManager.Resolve<IUserRepository>();
      var buildingId = (int)httpContext.Session["BuildingId"];
      var userName = httpContext.User.Identity.Name;
      var user = repo.GetByName(userName);
      var userRolesInBuilding = repo.GetRolesForUserInBuilding(user.UserId, buildingId);
      
      foreach (var role in Roles.Split(','))
      {
          if (userRolesInBuilding.Contains(role.Trim()))
          {
              return true;
          }
      }
      
      return false;
      

      }

    • 最后,这是如何在控制器或操作级别使用它。

      [BuildingAthorize(角色=“管理员”)]

我还在布局中添加了一个 ddl 以让用户更改建筑物并设置新的 BuildingId 覆盖 session/db 的值。这样,用户可以在同一会话期间在不同的酒店工作,并且只能访问他对该特定酒店拥有的区域和功能。

于 2013-09-15T07:33:58.510 回答