在MVC(ASP)中为相同数据实现多个角色

时间:2016-06-07 08:07:19

标签: asp.net asp.net-mvc

示例:

我们有两种用户类型。

  • SupplierUser
  • FactoryUser

它们都与基本相同的数据接口,但一般而言,FactoryUsers可以编辑比SupplierUser更多的此类信息。

使用ASP.NET 4.5,我正在使用MVC实现所有这些。

一些总结用例:(假设已登录)

FactoryUser:

  • 可编辑消息页面,向供应商显示其最新公告。
  • 订单确认页面和订单查看页面。
  • 供应商编辑页面(用于更新多个供应商的地址等)

SupplierUser:   - 可以查看来自特定工厂的消息。   - 可以创建订单,发送和查看。   - 可以编辑自己的信息

正如您所看到的,这只是通过各种权限进行的大量信息编辑。我的问题是,我应该在哪里开始分离?

关于:

  1. 模型 - 我认为这个与数据库保持一致
  2. ViewModels - 我是否为每个角色编写不同的视图?如果是这样,2个文件/类?
  3. 控制器 - 同样,我写不同的功能??类?如果是这样,那么具有[授权角色]的重点是保护免受未经授权的访问。不打算拆分?
  4. 观点 - 我是否尝试对大多数部分使用相同的视图,并且只是在某种程度上包含了关于他们是否有"编辑"按钮与否?
  5. 部分视图 - 可以用于"编辑"视图上可能有也可能没有的按钮?
  6. 查看布局 - ?
  7. 过滤器 - 我可以做一些奇特的逻辑并将所有内容放在完全2个不同的文件夹(整个MVC)中,然后在路由/授权级别将其拆分
  8. 路由 - ?
  9. 在上面的每一个中,我都可以看到根据用户类型分割逻辑的可能性。但是,当然,我希望以最简单,最理智的方式做到这一点。

    是否有某些文件指明了应该如何做,或者其他任何明智的人在此之前做过这件事并遇到所有问题?

    由于 (第一个问题!)

1 个答案:

答案 0 :(得分:2)

执行此操作的一种方法是创建功能。例如View Orders, Create Order, Update Order, Delete Order

然后会将这些features分配给Role - 并且可以将角色分配给User

所以DB看起来像这样:

enter image description here

现在,当用户登录时,您将读取分配给用户的所有功能并将其保存在会话中(创建SessionHandler类)。

// Login Function - You can call from Controller
public UserDTO Login(string username, string password)
{
 var user = dbContext.Users.FirstOrDefault(s => s.Username == username && s.Password == password);

if(user == null) return null; // login failed

var model = new UserDTO()
{
    UserId = user.UserId,
    Features = user.Role.Features.Select(s => s.FeatureName).ToList()
};


return model;

}

UserDTO类的示例

public class UserDTO
{
     public int UserId {get;set;}
     public List<string> Features {get;set;}
}

SessionHandler

的示例
public class SessionHandler
{
    private const string SessionKey = "UserSession";

    public static UserDTO UserSession
    {
        get
        {
            return HttpContext.Current.Session[SessionKey] != null
                       ? (UserDTO)HttpContext.Current.Session[SessionKey]
                       : null;
        }
        set { HttpContext.Current.Session[SessionKey] = value; }
    }
}

因此,在您的控制器中调用Login函数并分配到UserSession中的SessionHandler

[HttpPost]
public ActionResult Login(LoginModel model)
{
   var user = Login(model.username, model.password);

   if(user == null) return View(model);

   SessionHandler.UserSession = user;

   // TODO: redirect to Home Page - after login

    return RedirectToAction("Index", "Home");
}

然后,您可以在视图中执行的操作是检查用户是否可以执行某项操作,例如如果您在查看订单页面上 - 如果用户没有权限,您可以隐藏创建订单按钮:

    @model WhateverDTO

    // Check if user has Create Order Feature in Role 

    @if (SessionHandler.UserSession.Features.Contains("Create Order"))
    {
// Yes, User has permission - then Render the Button

     <button> Create Order </button>

    }

您还可以在Controller(服务器端)中添加检查 - 使用授权属性为您的应用程序提供额外的安全性:

public class CustomAuthorizeAttribute : AuthorizeAttribute
{

    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        if (httpContext == null)
            throw new ArgumentNullException("httpContext");
        if (httpContext.Session == null)
            return false;

        // Checking Authenticaiton
        var userSettings = SessionHandler.UserSession;
        if (userSettings == null)
            return true;

        //Checking Authorization
        if (Roles.Length == 0)
            return true;


        var actionFeatures = Roles.Split(',');
        if (!actionFeatures.Any(s => userSettings.Features.Contains(s)))
            throw new UnauthorizedAccessException("You do not have permission to perform this action.");
        return true;
    }
}

然后装饰你的行动,

[CustomAuthorize(Roles = "Create Order")]
// Pass feature name for Roles - if user doesn't have permission to Create Order - the "You do not have permission to perform this action." exception will get thrown
public ActionResult CreateOrder()
{
  return View(new CreateOrderDTO());
}

[HttpPost]
[CustomAuthorize(Roles = "Create Order")]
// Pass feature name for Roles - if user doesn't have permission to Create Order - the "You do not have permission to perform this action." exception will get thrown
public ActionResult CreateOrder(CreateOrderDTO model)
{

  return View(model);
}

上述方法的好处是,您可以根据需要添加任意数量的用户角色,而无需更改代码。

模型 - 我认为这个与数据库保持一致

模型相同 - 相同的DB相同模型

ViewModels - 我是否为每个角色编写不同的视图?如果是这样,2个文件/类?

不,不要复杂化 - 使用相同的ViewModel / DTO

控制器 - 同样,我会写不同的功能吗?类?如果是这样,那么具有[授权角色]的重点是保护免受未经授权的访问。不打算拆分?

无需单独的操作/视图或控制器

观点 - 我是否尝试对大多数部分使用相同的视图,并且只是在某种程度上包含了关于他们是否具有&#34;编辑&#34;按钮与否?

是,使用相同的视图 - 根据用户角色/功能隐藏/显示操作

部分视图 - 可以将它们用于&#34;编辑&#34;视图上可能有也可能没有的按钮?

无需按钮的部分视图

查看布局 - ? 过滤器 - 我可以做一些奇特的逻辑并将所有内容放在完全2个不同的文件夹(整个MVC)中,然后在路由/授权级别将其拆分 路由 - ?

没有