使用反射和枚举进行 MVC 应用程序访问的逻辑控制是否安全?

发布于 2024-12-21 14:14:50 字数 1158 浏览 1 评论 0原文

尝试管理对网站的访问我创建了一些必要的实体 在此处输入图像描述

目标是为我的 MVC 应用程序的某些控制器的操作方法使用自定义权限属性。

[Permissions(PermissionType.SomePermissionName, CrudType.CanDelete)]
public ActionResult SomeAction()
{
}

对于此操作,我有两个枚举

[Flags]
public enum CrudType
{
    CanCreate = 0x1,
    CanRead = 0x2,
    CanUpdate = 0x4,
    CanDelete = 0x8,
}

[Flags]
public enum PermissionType
{
   SomePermissionName = 0x1,
   //... 
}

现在我想要下面的方法来检查权限

public static bool CanAccess(RolePermissions rp, CrudType crudType)
{
    var pInfo = rp.GetType().GetProperties();
    var res = pInfo.FirstOrDefault(x => x.Name == crudType.ToString());
    if(res != null)
    {
        return Convert.ToBoolean(res.GetValue(rp, null));
    }
    return false;
}

它效果很好,但是在这里使用反射安全吗?这是一个好的风格吗?
还有一个问题是关于这样一段代码的

var permission = PermissionService.GetByName(permissionType.ToString());

:这里我尝试使用 PermissionType 枚举中的一些命名常量从数据库获取权限对象。
在这两种情况下,正确的工作取决于枚举和某些表字段或记录之间的关系。另一方面,我有一个很好的控制逻辑的机制(在我看来)。 这是个好办法吗?

Trying to manage access to a web site I created some necessary entities
enter image description here

The goal is use a custom permission attribute for some controller's action method of my MVC application.

[Permissions(PermissionType.SomePermissionName, CrudType.CanDelete)]
public ActionResult SomeAction()
{
}

For this operation I have two enums

[Flags]
public enum CrudType
{
    CanCreate = 0x1,
    CanRead = 0x2,
    CanUpdate = 0x4,
    CanDelete = 0x8,
}

[Flags]
public enum PermissionType
{
   SomePermissionName = 0x1,
   //... 
}

Now I want the method below to check permissions

public static bool CanAccess(RolePermissions rp, CrudType crudType)
{
    var pInfo = rp.GetType().GetProperties();
    var res = pInfo.FirstOrDefault(x => x.Name == crudType.ToString());
    if(res != null)
    {
        return Convert.ToBoolean(res.GetValue(rp, null));
    }
    return false;
}

It works good but is it safe to use reflection here? Is it a good style?
One more question is about such piece of code

var permission = PermissionService.GetByName(permissionType.ToString());

Here I'm trying to get a permission object from a database using some named constant from the PermissionType enum.
In both cases the correct work depends on relationships between enums and some table fields or records. On other side I have a good mechanism of controlling logic (as it seems to me).
Is that a good way?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

御弟哥哥 2024-12-28 14:14:50

另一次编辑
在您的情况下,为 RolePermissions 类创建一个只读属性 ExistingPermissions 是有意义的,并将四个布尔值合并为一个 CrudType在该属性获取器内。然后你就可以执行rp.ExistingPermissions.HasFlag(permissionToCheck)

已编辑

感谢@DevDelivery 指出了这个问题 - 很好。不幸的是,固定的解决方案并不像我希望的那么漂亮,所以在这种情况下,采用 @DevDelivery 的方法可能是有意义的。

由于您将 CrudType 作为“位字段”,因此您可以使用更简洁的方法(更少的代码和更好的可读性):

public static bool CanAccess(RolePermissions rp, CrudType permissionToCheck)
{
    CrudType existingPermissions = 
                                SetPermissionFlag(CrudType.CanCreate, rp.CanCreate) |
                                SetPermissionFlag(CrudType.CanRead, rp.CanRead) | 
                                SetPermissionFlag(CrudType.CanUpdate, rp.CanUpdate) |
                                SetPermissionFlag(CrudType.CanDelete, rp.CanDelete);

    return existingPermissions.HasFlag(permissionToCheck);
}

public static CrudType SetPermissionFlag(CrudType crudType, bool permission)
{
    return (CrudType)((int)crudType * Convert.ToInt32(permission));
}

与您的解决方案相比,缺点是您必须修改此方法,以防您添加更多操作(现有的CanRead等)。

ANOTHER EDIT
In your case it would make sense to create a readonly property ExistingPermissions for the RolePermissions class, and do the merging of the four booleans into one CrudType within that property getter. Then you can just do rp.ExistingPermissions.HasFlag(permissionToCheck).

EDITED

Thanks to @DevDelivery for pointing out the issue - good catch. Unfortunately the fixed solution isn't as pretty as I was hoping for, so in this case it might make sense to go with @DevDelivery's approach.

Since you have your CrudType as "bitfields", you can use a cleaner approach (less code and better readability):

public static bool CanAccess(RolePermissions rp, CrudType permissionToCheck)
{
    CrudType existingPermissions = 
                                SetPermissionFlag(CrudType.CanCreate, rp.CanCreate) |
                                SetPermissionFlag(CrudType.CanRead, rp.CanRead) | 
                                SetPermissionFlag(CrudType.CanUpdate, rp.CanUpdate) |
                                SetPermissionFlag(CrudType.CanDelete, rp.CanDelete);

    return existingPermissions.HasFlag(permissionToCheck);
}

public static CrudType SetPermissionFlag(CrudType crudType, bool permission)
{
    return (CrudType)((int)crudType * Convert.ToInt32(permission));
}

The drawback compared to your solution is that you will have to modify this method in case you add more operations (to the existing CanRead, etc.).

画骨成沙 2024-12-28 14:14:50

使用反射会对性能产生影响,并且后期绑定意味着更改枚举的名称
或者属性不会被编译器捕获。

另外,这段代码非常难以理解,因此难以维护。

这里只有 4 个选项需要检查。简单的 switch 语句更容易、更快、更简洁。

如果您试图允许更改数据库或允许第三方组件引入新权限,那么使用反射是有意义的。

Using reflection has a performance impact and the late-binding means that changing a name of a enum
or property will not get caught by the compiler.

Plus, this code is very hard to understand, thus difficult to maintain.

Here there are only 4 options to check. A simple switch statement is easier, faster, and cleaner.

Using reflection would make sense if you were trying to allow for changes to the database or for third-party components to introduce new permissions.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文