【问题标题】:How can I restrict users to only edit their data with Linq To SQL?如何限制用户只能使用 Linq To SQL 编辑他们的数据?
【发布时间】:2012-07-09 13:08:17
【问题描述】:

背景: 我一直在使用 C# 在 ASP.NET 4.0 中开发一个小型概念验证 Web 应用程序,并且我一直在使用 Linq To SQL,因为它既快速又简单。我现在必须限制一个用户在同一个数据库中查看另一个用户的数据。所以我在我的大多数表格中添加了一个“帐户”列,我想在允许他们访问之前检查当前用户是否与他们正在查看/编辑的数据是同一帐户的成员。

一种我不太满意的可能解决方案: 我可以简单但痛苦地检查我所有的 Linq To SQL 查询并添加一个 if 语句来进行这样的检查:

MyDataContext DB = new MyDataContext();
//get the current user's information from the DB
USER myUser = DB.USERs.Where(j => j.USR_EMAIL == User.Identity.Name).FirstOrDefault();
//get the object to edit
MYOBJECT myObject= DB.MYOBJECTs.Where(j => j.ID == IdFromQueryString).FirstOrDefault();
//compare the user's account with the object's account they are now trying to view
if(myUser.AccountID == myObject.AccountID)
{
    //display the object
}
else
{
    //display error message
}

这将是整个应用程序中要做的大量工作,更不用说重复和出错的机会了。维护起来也很痛苦,如果我忘记为查询添加这个,我会留下一个安全漏洞。

问题: 有没有办法为每个表执行一次,每次我使用 Linq To SQL 进行查询时它都会自动检查?或者有没有更好的方法来解决这个问题?

【问题讨论】:

    标签: c# asp.net .net linq-to-sql


    【解决方案1】:

    您应该使用Repository 模式,而不是直接访问Contest.Users,而是始终访问Repository.Users。然后您可以更改存储库以将Users 公开为from u in InternalContext.Users where u.AccountId = currentAccountId select u,从而强制执行范围。巧合的是这个技术是called a scope in Rails...

    下一个最好的方法是使用 DataLoadOptions 将 lambda 过滤器与您的实体相关联,请参阅 How to: Filter at the DataContext Level (LINQ to SQL)。您需要将此添加到您创建的每个上下文中。同样,重构代码以从方法中获取数据上下文(或者更好的是,实现存储库模式...)会有很大帮助。

    最后,您可以在后端通过可更新视图和context_info() 实现这一点,但我强烈反对这样做。

    PS。我希望您将account_id 设置为表上每个聚集索引中最左边的键,并使实体id 主键非聚集,对吗?否则你的表现会下降。

    【讨论】:

    • 我刚刚意识到我要给出的答案与你答案的第一部分基本相同,但我要强调你如何让你的存储库返回 IQueryable(s) 以便进一步过滤可以在数据库级别有效地完成。 Repository 模式非常适合与 IQueryable(s) 一起使用;谢谢你提醒我。
    • 你是冠军。不,我没有按照您的描述进行索引,但我现在会。存储库模式听起来不错 - 你能推荐任何可以帮助我开始使用它的资源(一个例子会很好)吗?另外,感谢 JayC 提到 IQueryables - 我之前没有听说过这些
    • @Dean:一切都是 LINQ 基本上是一个 IQueryable。至于存储库模式,这个主题更复杂,它与 TDD(测试驱动开发)和 IoC(控制反转)等概念结合在一起。从Walkthrough: Using TDD with ASP.NET MVC 开始。 Channel9上有一个很好的教程,但我就是找不到。
    【解决方案2】:

    抱歉,这两个对象都有可用的 AccountID 吗?如果是这样,您是否有任何理由无法通过他们的 Accountid 加入他们?

    var query = from o in DB.MYOBJECTs.Where(w => w.ID == IdFromQueryString)
                join u in DB.USERs.Where(w => w.USR_EMAIL = User.Identity.Name) on o.AccountID equals u.AccountID
                select o;
    

    【讨论】:

    • 是的,我对这两个对象都有可用的 AccountId。感谢您提供更简洁的代码,它绝对比我拥有的更好!但是,我理想的解决方案是我可以在一个地方管理此代码
    【解决方案3】:

    两种可能的方法:

    • 使用存储过程而不是直接查询来访问数据;仅授予用户对这些存储过程的权限(即没有对数据库的一般读取访问权限)并让存储过程强制执行访问限制。
    • 通过单独的服务代理对数据库的所有访问 - 该服务是唯一对数据库具有一般访问权限的事物,并且可以强制执行访问限制。

    这些从根本上与您当前包装每个查询的策略没有太大不同,但可能更易于管理。

    【讨论】:

    • 不要忘记 sql 函数...与存储过程不同,这些函数可以组合成任意(且相对高效)的 sql 查询。不过,我不知道这对 linq-to-sql 的翻译效果如何。
    • 我真的不知道你说的单独服务是什么意思,你能给我举个例子吗?
    • 有一个单独的进程,这是唯一可以访问数据库并通过某种形式的 RPC 与该进程对话的进程。这为您提供了非常强的关注点分离,这有一些优势:例如,即使您的主程序存在安全漏洞,您也不会损害对数据库的访问(当然,服务中的漏洞是另一个问题)。不过,我怀疑这对于您的用例来说可能太重了。
    • 好的,是的,这对于我的特定应用程序来说有点矫枉过正,但对于其他项目需要牢记。谢谢!
    猜你喜欢
    • 2015-02-25
    • 2019-09-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多