2

背景: 我一直在使用 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 进行查询时它都会自动检查?或者有没有更好的方法来解决这个问题?

4

3 回答 3

3

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

下一个最好的方法是将DataLoadOptionslambda 过滤器与您的实体相关联,请参阅如何:在 DataContext 级别进行过滤 (LINQ to SQL)。您需要将此添加到您创建的每个上下文中。同样,重构代码以从方法中获取数据上下文(或者更好的是,实现存储库模式......)将有很大帮助。

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

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

于 2012-07-10T05:22:40.870 回答
1

抱歉,这两个对象都有可用的 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;
于 2012-07-10T05:08:25.687 回答
0

两种可能的方法:

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

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

于 2012-07-10T05:04:11.723 回答