层设计:在哪里检查数据库读取/更新的权限?

前端之家收集整理的这篇文章主要介绍了层设计:在哪里检查数据库读取/更新的权限?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
在大多数情况下,您希望用户只能访问由用户自己创建的数据库中的实体.例如,如果有一个由User1创建的日历,则只有User1应该能够读取,更新或删除该特定日历及其在数据库中的内容.这不是一般的授权 – 在我的项目中,已经有一个基于角色的授权组件,用于检查用户是否属于“日历编辑器”角色,但不检查特定用户是否被允许访问具体日历.

所以最终必须比较当前请求的user-id和表示所请求的日历所有者的user-id.但我想知道在哪里做这个我的想法:

>我可以在DAO层面上做.但是,每个DAO方法都需要一个额外的参数来表示用户id,这些参数使得这些方法更加冗长并减少了可重用性.

例如.

def findCalById(id:Int):Future [Option [Calendar]]

def findCalById(id:Int,ownerId:Int):Future [Option [Calendar]]

一个优点是,权限检查基本上在查询级别完成,这意味着如果用户无法访问日历,则不会从数据库返回日历.但是再一次:如果在某些情况下没有返回日历,那么您如何区分不存在的日历和当前用户无法访问的现有日历?两种不同的场景,产生相同的结果.
>另一种选择可能是将DAO保留在此之外,并在服务层或类似的东西中进行检查.这意味着在DAO返回请求的日历之后执行该检查.这种方法听起来比另一种更灵活,但也意味着在用户无法访问所请求的日历的情况下,所请求的日历仍然消耗带宽和内存,因为在任一种情况下都从数据库获取带宽和内存.

也许有其他选项我甚至没有考虑.有没有最佳做法?

Btw:我的Web应用程序没有日历,这只是一个例子来说明问题.

解决方法

我认为,关键是要考虑当你说DAO方法“降低可重用性”时你的意思是什么.如果您强制执行用户访问权限的要求对于DAO的所有应用程序都是通用的,那么在DAO级别执行此操作实际上可以提高可重用性,而不是减少它们:使用DAO的所有用户将能够从这些检查中获益,而不必执行它们他们自己.

您可以将用户ID设置为隐式参数,使这些方法对上游用户更友好.你也可以让它返回一个Try(或者也许是一个)来解决你对区分缺失和不可访问的对象情况的关注:

case class UserId(id: Int)
def findCalById(id: Int)(implicit user: UserId): Future[Try[Option[Calendar]]] = ???

然后,呼叫者可以这样做:

implicit val currentUser = UserId(request.getUserId)
dao.findCalById(request.getCalendarId).map { 
    case Failure(IllegalAccessException()) => "You are not allowed to use this calendar"
    case Return(None) => "Calendar not found"
    case Return(Some(cal)) => calendarToString(cal)
}

另一方面,如果可能的情况下DAO可能在没有用户上下文的情况下被使用(也许是“管理员”应用程序),则可以考虑将其子类化以向“常规应用程序”提供访问控制,也许,只需做一个额外的角色,允许用户访问有关所有权的所有日历,然后在您的管理应用程序中使用该“超级用户”.

我不用担心在检查访问之前必须加载对象的成本(即使对象加载真的很贵,它应该是一个罕见的事情,有人试图访问他不拥有的对象).我认为,反对服务层方法的更强有力的论据是代码的可重用性和模块化:具有公共接口的DAO类的存在表明它至少可以被多个组件重用.看来愚蠢的是要求所有这样的组件实现自己的访问检查,特别是考虑到这样的合同是不可执行的:没有办法确保在几年后决定使用你的DAO类的人,会记住这个要求(或者关心阅读评论).如果您正在生成访问数据库的图层,那么您也可以使其对某些东西有用.

原文链接:https://www.f2er.com/mssql/81612.html

猜你在找的MsSQL相关文章