![]() |
1
29
我见过很多人试图让基于角色的安全性做一些它从未打算做的事情,但您已经超过了这一点,所以这很酷:) 基于角色的安全性的替代方案是基于ACL的安全性,我认为这就是您在这里需要的。 您仍然需要检索产品的ACL,然后检查用户是否具有该产品的正确权限。这是如此的上下文敏感和交互繁重,以至于我认为纯粹的声明性方法既过于死板又过于隐式(即,您可能没有意识到在向某些代码添加单个属性时会涉及多少数据库读取)。
如果您只想确保用户有权继续,可以发出断言:
如果未授予权限,则应引发异常。
您可能想看看System.Security.AccessControl.FileSystemSecurity,以获得有关ACL建模的灵感。 如果当前用户与Thread.CurrentPrincipal相同(在ASP.NET MVC、IIRC中就是这种情况),则可以将上述权限方法简化为:
或
因为用户是隐式的。您可以查看System.Security.Permissions.PrincipalPermission以获得灵感。 |
![]() |
2
16
从您描述的内容来看,您似乎需要某种形式的用户访问控制,而不是基于角色的权限。如果是这种情况,则需要在整个业务逻辑中实现它。您的场景听起来好像可以在服务层中实现它。 基本上,您必须从当前用户的角度实现ProductRepository中的所有功能,并且产品被标记为该用户的权限。 听起来比实际情况更难。首先,您需要一个用户令牌界面,其中包含uid和角色列表的用户信息(如果您想使用角色)。您可以使用IPrincipal,也可以按照
然后在控制器中,将用户令牌解析到存储库构造函数中。
如果您使用的是FormsAuthentication和自定义IUserToken,那么您可以围绕IPrincipal创建一个包装器,这样您的ProductRepository的创建方式如下:
现在,所有IPProductRepository函数都应该访问用户令牌以检查权限。例如:
如果您想获得所有产品的列表,可以在数据访问代码中根据权限进行查询。在本例中,使用左连接查看多对多表是否包含UserToken.Uid和productId。如果存在联接的右侧,则您知道用户具有该产品的权限,然后您可以设置product.CanEdit布尔值。 使用此方法,您可以在视图中使用以下内容(其中模型是您的产品)。
或者在你的控制器里
此方法的好处是,安全性内置于服务层(ProductRepository)中,因此它不由控制器处理,也不能被控制器绕过。 主要的一点是,安全性放在您的业务逻辑中,而不是控制器中。 |
![]() |
3
3
.NET Reflector 查看AuthorizeAttribute是如何实现的,并对其执行您自己的逻辑。 它所做的是继承FilterAttribute并实现IAuthorizationFilter。我现在不能测试这个,但是类似的东西应该可以用。
您可能还可以将获取的产品/用户存储在filterContext.Controller.TempData中,这样您就可以在控制器中获取它,或者将它存储在某个缓存中。 编辑:我刚刚注意到关于编辑链接的部分。我能想到的最好的方法是从属性中分解授权部分,并为其生成一个可以在视图中使用的HttpHelper。 |
![]() |
4
1
我倾向于认为授权是业务逻辑的一部分(或者至少在控制器逻辑之外)。我同意上面kevingessner的观点,授权检查应该是获取物品调用的一部分。在他的OneException方法中,您可以通过以下方式显示登录页面(或在web.config中配置的任何内容):
而不是让UserRepository.GetUserSomehowFromTheRequest()调用 对于action方法,我会这样做一次(例如,在Controller.OnAuthorization方法的重写中),然后将该数据粘贴到控制器基类中的某个位置以供以后使用(例如,属性)。 |
![]() |
5
1
我认为,期望控制器/模型代码控制视图呈现的内容是不现实的,这违反了关注点的分离。控制器/模型代码可以在视图模型中设置一个标志,视图可以使用该标志来确定它应该做什么,但我认为您不应该期望控制器/模型和视图都使用一个方法来控制对模型的访问和渲染。 话虽如此,您可以用两种方法中的任何一种来实现这一点——这两种方法都涉及到一个视图模型,除了实际模型之外,还包含一些视图使用的注释。在第一种情况下,可以使用属性控制对操作的访问。这是我的首选,但需要独立地装饰每个方法——除非控制器中的所有操作都具有相同的访问属性。 为此,我开发了一个“角色或所有者”属性。它验证用户是否处于特定角色,或者是否是该方法生成的数据的所有者。在我的例子中,所有权是由用户和相关数据之间的外键关系控制的——也就是说,您有一个ProductOwner表,并且需要有一行包含产品和当前用户的产品/所有者对。它与普通的authorized属性的不同之处在于,当所有权或角色检查失败时,用户将被定向到错误页面,而不是登录页面。在这种情况下,每个方法都需要在视图模型中设置一个标志,指示可以编辑模型。 或者,您可以在控制器(或基本控制器)的ActionExecuting/ActionExecuted方法中实现类似的代码,以便它在所有控制器中一致地应用。在这种情况下,您需要编写一些代码来检测正在执行的操作类型,以便根据相关产品的所有权确定是否中止该操作。相同的方法将设置标志以指示可以编辑模型。在这种情况下,您可能需要一个模型层次结构,以便可以将模型强制转换为可编辑模型,从而可以设置属性,而不考虑特定的模型类型。 与使用属性相比,这个选项对我来说似乎更为复杂。对于属性,您可以对其进行设计,使其将各种表和属性名称作为属性的属性,并使用反射根据属性的属性从存储库中获取适当的数据。 |
![]() |
6
0
回答我自己的问题(eep!),专业ASP.NET MVC 1.0(NerdDinner教程)的第1章为我推荐了一个类似的解决方案:
为了避免让我饿着肚子吃晚饭,本教程继续在匹配的POST-Action方法和Details视图(实际上是Details视图的子部分)中重复立即实现业务规则的代码,因此本教程并没有添加任何内容 这是否违反了SRP?如果业务规则发生更改(例如,任何拥有RSVP的人都可以编辑晚餐),则必须同时更改GET和POST方法以及视图(以及删除操作的GET和POST方法和视图,尽管这在技术上是一个单独的业务规则)。 将逻辑拉入某种权限仲裁器对象(正如我在上面所做的)是否尽可能好? |
![]() |
7
0
这是正确的,但是可以将所有权限检查封装到一个方法中,如
您只需提供ProductPermissionService.UserPermission,即可返回用户对给定产品的权限。通过使用权限枚举(我想我已经掌握了正确的语法…)并将权限与
|
![]() |
8
0
|