阻止用户访问类字段

时间:2014-12-26 04:40:31

标签: c# .net

我正在使用C#4.0编写一个DLL,它将被几个基于C#.NET的桌面应用程序使用(让他们称之为AppA和AppB)。要求AppA能够使用某些课程。选定的字段/属性/功能甚至不可用于AppB。我的方法是对这些属性使用internal修饰符,并通过在DLL的InternalsVisibleTo属性中指定AppA的程序集名称来授予对AppA的访问权限。但是在某些属性中也需要internal修饰符,这些属性将在DLL的其他部分中访问但不能被AppA访问。现在似乎有太多internal暴露给AppA,而AppA无法访问它。

换句话说,请考虑以下属性:

class A
{
    internal int ReallyInternal {get; set;}
    internal int AppAInternal {get; set;}
}

如果我对AppA使用InternalsVisibleTo属性,那么ReallyInternalAppAInternal属性都会向AppA公开 - 其中ReallyInternal不应该公开APPA。

如何解决这个问题?有没有其他方法可以实现这种情况?

背景

在进入InternalsVisibleTo方法之前,我们想到了其他方法,比如拥有不同的界面等。我写的类库将由多个应用程序使用。我希望各种应用程序的界面相同。

TT4视为DLL中的一个类。它的属性将通过串行通信从物理设备填充。

TT4 tt4 = new TT4();
// Some code to populate tt4 object

MessageBox.Show(tt4.SerialNumber);
tt4.SerialNumber = "123";

由于tt4对象将代表物理设备,因此并非所有应用程序都可以修改其所有属性。这没有意义,如果我们允许,那么任何应用程序都可以更改设备的序列号。 (是的,SerialNumber可以写回设备)。

我们只有一个应用程序(例如AppA)可以设置和更改SerialNumber。其他应用程序不应该这样做。将SerialNumber的setter设为internal并通过InternalsVisibleTo向AppA授予权限,从而阻止了这一过程。

请注意,为库提供两个类不是解决方案。说,我已经为TT4 - TT4(不能写SerialNumber)和TT4Super(可以编写SerialNumber)实现了两个类。当DLL被提供给客户端时,他们仍然可以看到TT4Super并使用它。

我不是其他应用程序的开发者,我无法控制它们。

2 个答案:

答案 0 :(得分:2)

这样做的一种方法是将应该向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并不是一个访问修饰符。它的主要目的是使单元测试更容易,不能在生产组件之间进行通信。

答案 1 :(得分:1)

您是否主要担心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;
    }
}

这至少应该阻止任何人轻易使用反射来规避你的防御。