阻止用户访问类字段
本文关键字:字段 访问 用户 | 更新日期: 2023-09-27 18:35:22
我正在使用C# 4.0编写一个DLL,它将由几个基于C# .NET的桌面应用程序使用(我们称之为AppA和AppB)。要求 AppA 能够使用某些类的选定字段/属性/函数,这些字段/属性/函数甚至对 AppB 不可用。我的方法是对这些属性使用internal
修饰符,并通过在 DLL 的属性中指定 AppA 的程序集名称来授予对 AppA InternalsVisibleTo
访问权限。但是internal
在某些属性中也需要修饰符,这些修饰符将在 DLL 的其他部分中访问,但不能由 AppA 访问。现在看来,有太多internal
暴露在 AppA 中,而 AppA 不应该访问这些。
换句话说,请考虑以下属性:
class A
{
internal int ReallyInternal {get; set;}
internal int AppAInternal {get; set;}
}
如果我对 AppA 使用 InternalsVisibleTo
属性,则ReallyInternal
和AppAInternal
属性都将向 AppA 公开 - ReallyInternal
不应该向 AppA 公开。
如何解决这个问题?还有其他方法可以实现此方案吗?
背景
在采用InternalsVisibleTo
方法之前,我们考虑了其他方法,例如使用不同的接口等。我正在编写的类库将由多个应用程序使用。我希望跨应用程序的界面相同。
请考虑TT4
DLL 中的一个类。它的属性将通过串行通信从物理设备填充。
TT4 tt4 = new TT4();
// Some code to populate tt4 object
MessageBox.Show(tt4.SerialNumber);
tt4.SerialNumber = "123";
由于对象将表示物理设备tt4
因此并非所有应用程序都可以修改其所有属性。这没有意义,如果我们允许这样做,那么任何应用程序都可以更改设备的序列号。(是的,序列号可以写回设备)。
我们只有一个应用程序(例如 AppA)能够设置和更改序列号。其他应用程序不应这样做。通过将序列号的设置器设置为internal
并通过InternalsVisibleTo
授予对 AppA 的权限来防止它。
请注意,为库提供两个类不是解决方案。比如说,我已经为TT4
实现了两个类 - TT4
(不能写序列号)和TT4Super
(可以写序列号)。当 DLL 将提供给客户端时,他们仍然可以看到TT4Super
并使用它。
我不是其他应用程序的开发人员,也无法控制它们。
一种方法是将应该向 AppA 公开的所有成员提取到抽象类(或一般的父类)并使它们protected internal
。要从 AppA 访问它们,它必须从抽象类继承。例如
public abstract class ParentA
{
internal int ReallyInternal {get; set;}
protected internal int AppAInternal {get; set;}
}
AppA 通过以下方式访问它:
internal class AinAppA : ParentA
{
internal AinAppA()
{
this.AppAInternal = 1; // can access parents protected members
// this.ReallyInternal = 2; // but pure internal members are not visible
}
}
作为旁注,InternalsVisibleTo
并不意味着是访问修饰符。它的主要目的是使单元测试更容易,而不是启用生产程序集之间的通信。
您最担心 AppB 的设计者会对您的 DLL 执行恶意操作,还是您只是想阻止他们无意中执行某些操作?让你的成员internal
并不能真正阻止某人通过反思来伤害他们,如果他们愿意的话。
您可以使用的一种(诚然不是很好)方法是通过检查调用程序集来公开这些成员,但防止除 AppA 以外的任何人使用它们:
private void VerifyCaller(Assembly a)
{
if (a == Assembly.GetExecutingAssembly()) { return; }
var name = a.GetName();
if(name.Name == "AppA" && name.GetPublicKey() == appAPublicKey) { return; }
throw new InvalidOperationException("You can't access this");
}
private string _serialNumber;
public string SerialNumber
{
get { return _serialNumber; }
set
{
VerifyCaller(Assembly.GetCallingAssembly());
_serialNumber = value;
}
}
这至少应该防止任何人轻易地使用反射来规避你的防御。