惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Google DeepMind News
Google DeepMind News
H
Help Net Security
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
V
Vulnerabilities – Threatpost
MongoDB | Blog
MongoDB | Blog
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
A
Arctic Wolf
The GitHub Blog
The GitHub Blog
Security Latest
Security Latest
G
GRAHAM CLULEY
Cyberwarzone
Cyberwarzone
S
Schneier on Security
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
P
Privacy & Cybersecurity Law Blog
IT之家
IT之家
D
Darknet – Hacking Tools, Hacker News & Cyber Security
博客园 - 聂微东
T
Threat Research - Cisco Blogs
AWS News Blog
AWS News Blog
The Hacker News
The Hacker News
B
Blog RSS Feed
云风的 BLOG
云风的 BLOG
Scott Helme
Scott Helme
P
Proofpoint News Feed
T
The Exploit Database - CXSecurity.com
L
LangChain Blog
F
Full Disclosure
I
Intezer
V
V2EX
C
Cyber Attacks, Cyber Crime and Cyber Security
Cisco Talos Blog
Cisco Talos Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Spread Privacy
Spread Privacy
美团技术团队
Engineering at Meta
Engineering at Meta
C
Cybersecurity and Infrastructure Security Agency CISA
罗磊的独立博客
T
Tenable Blog
D
DataBreaches.Net
M
MIT News - Artificial intelligence
S
Securelist
C
CERT Recently Published Vulnerability Notes
Recent Announcements
Recent Announcements
Microsoft Azure Blog
Microsoft Azure Blog
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
NISL@THU
NISL@THU
The Register - Security
The Register - Security
L
LINUX DO - 热门话题
P
Palo Alto Networks Blog

博客园 - 孤城浪子

[原]一步一步自己制作弹出框 [转]获取窗口 高 、宽 的JS代码 PHP连接mysql数据库 - 孤城浪子 - 博客园 PHP文件上传 动态调用Web Service - 孤城浪子 - 博客园 [转]ASP.NET 2.0 下加密解密算法的封装 [转]fckeidtor配置 [转]加解密技术 - 孤城浪子 - 博客园 [转]服务器推技术 [JavaScript]简单跟随鼠标移动的文字 排序算法 [仿照CloudGamer]写的颜色渐变 Asp.Net用SmtpClient发送邮件 项目中遇到的Vss和Sql问题 [JavaScript]拖动对象 - 孤城浪子 - 博客园 [JavaScript]飘浮文字 C#文件打散合并 C#调用Excel的宏 [网上整理]C#合并Excel
[转].Net 中的许可证机制
孤城浪子 · 2011-04-01 · via 博客园 - 孤城浪子

实验环境:Visual Studio 2005 + .Net Framework 2.0

主要命名空间:System.ComponentModel

主要类:

System.ComponentModel.License(为所有许可证提供 abstract 基类。向组件的特定实例授予许可证)

    System.ComponentModel.LicenseContext(指定何时可使用授权的对象,并且提供一种方法,用以获取为支持在其域内运行的许可证所需要的附加服务)

    System.ComponentModel.LicenseException(表示当组件不能被授予许可证时引发的异常。)

    System.ComponentModel.LicenseManager(提供属性和方法,用以将许可证添加到组件和管理 LicenseProvider

    System.ComponentModel.LicenseProvider(提供 abstract 基类以便实现许可证提供程序)

    System.ComponentModel.LicenseProviderAttribute(指定要与类一起使用的 LicenseProvider

许可证机制简介

.Net Framework中的许可证验证机制基于System.ComponentModel命名空间中的License、LicenseContext、LicenseException、LicenseManager、LicenseProvider和LicenseProviderAttribute六个类实现的。

License是一个抽象类,用于代表许可证主体;

LicenseContext中保存了许可证的上下文,其中UsageMode属性可以用来获取当前是运行时(runtime)还是设计模式(designtime);

LicenseException是许可证相关的异常,当许可证信息不可用时,在调用LicenseProvider(或其派生类)实例的GetLicense方法时将抛出此类型的异常;

LicenseManager是一个密封(sealed)类,LicenseManager提供了多个静态(static)方法用于验证许可证、获取许可证等操作;

LicenseProviderAttribute属性用于指定某一个类所采用的许可证提供程序(LicenseProvider)的具体类型;

LicenseProvider是一个抽象类,用于代表许可证验证机制提供程序。LicenseProvider的类型通过LicenseProviderAttribute属性提供给CLR,当调用LicenseManager的操作时,LicenseManager将根据LicenseProviderAttribute中所提供的LicenseProvider类型创建LicenseProvider实例,并进行相应操作。LicFileLicenseProvider基于文本文件的许可证机制。

LicFileLicenseProvider

LicFileLicenseProvider类是.Net Framework提供的一个简单的LicenseProvider实现。LicFileLicenseProvider类代表了.Net Framework提供的一种简单的基于文本文件的许可证验证机制。

通过上面的介绍,我们知道,要实现一套.Net中的许可证验证机制还需要一个类作为License的具体实现,而这个类在.Net Framework的类库中是无法找到的,但这个具体的实现类是肯定存在的。打开.Net Framework中自带的MSIL反汇编程序(ildasm.exe)打开System.dll查看,发现在LicFileLicenseProvider内部定义了一个私有类LicFileLicense,这个类就是License在这套许可证验证机制中的具体实现。

仍然在MSIL反汇编程序中,我们打开LicFileLicenseProvider类的GetLicense方法,在这个方法中会根据参数所传进来的目标类型的Type(在上面的图中就是MyClass的Type)查找到一个相应的扩展名为.lic的文本文件,并用FileStream读取其中的文本,然后调用IsKeyValid方法。

IL_0083: callvirt instance string [mscorlib]System.Type::get_FullName() // 获取目标类型的完整限定名

IL_0088: ldstr ".lic" // 在目标类型的完整限定名后面追加.lic组成许可证文件(.lic文件)的文件名

IL_008d: call string [mscorlib]System.String::Concat(string,

string,

string,

string)

IL_0092: stloc.s V_5

IL_0094: ldloc.s V_5

IL_0096: call bool [mscorlib]System.IO.File::Exists(string)

IL_009b: brfalse.s IL_00db

IL_009d: ldloc.s V_5

IL_009f: ldc.i4.3

IL_00a0: ldc.i4.1

IL_00a1: ldc.i4.1

IL_00a2: newobj instance void [mscorlib]System.IO.FileStream::.ctor(string,

valuetype [mscorlib]System.IO.FileMode,

valuetype [mscorlib]System.IO.FileAccess,

valuetype [mscorlib]System.IO.FileShare) // 开始用FileStream读取许可证文件

IL_00a7: stloc.s V_6

IL_00a9: ldloc.s V_6

IL_00ab: newobj instance void [mscorlib]System.IO.StreamReader::.ctor(class [mscorlib]System.IO.Stream)

IL_00b0: stloc.s V_7

IL_00b2: ldloc.s V_7

IL_00b4: callvirt instance string [mscorlib]System.IO.TextReader::ReadLine()

IL_00b9: stloc.s V_8

IL_00bb: ldloc.s V_7

IL_00bd: callvirt instance void [mscorlib]System.IO.TextReader::Close()

IL_00c2: ldarg.0

IL_00c3: ldloc.s V_8

IL_00c5: ldarg.2

IL_00c6: callvirt instance bool System.ComponentModel.LicFileLicenseProvider::IsKeyValid(string,

class [mscorlib]System.Type) // 调用IsKeyValid方法,进一步验证许可证是否有效

在IsKeyValid方法中,我们就可以明白为什么这种验证方式相当简单了。查看IsKeyValid方法的代码,发现,这个方法中仅仅是判断.lic文件中的文本是否是以目标类型的完整文件名开始的。

IL_0006: callvirt instance string System.ComponentModel.LicFileLicenseProvider::GetKey(class [mscorlib]System.Type)

IL_000b: callvirt instance bool [mscorlib]System.String::StartsWith(string) // 验证文本是否是以目标类型的完整限定名开始的

到这里,我们看到了LicFileLicenseProvider及LicFileLicense的运行机制。显然,在我们正式开发的时候这套验证机制是无法满足需求的,不过通过了解其中的逻辑,我们就可以很轻松的开发一套自己需要的许可证验证机制。

自定义许可证验证机制

创建一个新的项目,为了便于介绍我创建了一个控制台程序(LicTestConsole)。

向项目中添加许可证验证机制所需的类

License类的实现(SimpleLicense)

class SimpleLicense : License

{

private Type _Type;

public SimpleLicense(Type type)

{

if (type == null)

{

throw (new NullReferenceException());

}

_Type = type;

}

public override void Dispose()

{

// TODO: 根据需要插入垃圾回收的代码

}

public override string LicenseKey

{

get { return (_Type.GUID.ToString()); }

}

}

LicenseProvider类的实现(SimpleLicenseProvider)

public class SimpleLicenseProvider : LicenseProvider

{

public override License GetLicense(LicenseContext context, Type type, object instance, bool allowExceptions)

{

if (context.UsageMode == LicenseUsageMode.Runtime)

{

        // 这里是验证运行时的许可证的逻辑

        // 这里我采用了随机数(因为这样写代码较少),也就是说有时候能用有时候禁用,你可以根据自己具体的需要编写不同的验证逻辑

Random random = new Random();

if (random.Next(0, 2) == 1)

{

return (new SimpleLicense(type));

}

else

{

throw (new LicenseException(type));

}

}

else if (context.UsageMode == LicenseUsageMode.Designtime)

{

// TODO: 如果你想限制编辑模式下的许可证(所谓的开发许可证),在这里添加相应的逻辑

}

return (null);

}

}

向项目中添加一个类(TestWorker),并给TestWorker类加上LicenseProviderAttribute属性

[LicenseProvider(typeof(SimpleLicenseProvider))] // 这里指定了这个类中进行许可证验证的过程应采用SimpleLicenseProvider

public class TestWorker : IDisposable // 实现IDisposable接口,License的实例需要被显示的调用Dispose

{

private ArgType _ArgType = ArgType.None;

License _License = null; // _License 用于保存许可证信息

public TestWorker(string[] args)

{

ProcessArgs(args);

_License = LicenseManager.Validate(typeof(TestWorker), this); // 在这里调用LicenseManager进行许可证验证

                                     // 如果验证失败Validate方法将会抛出 LicenseException 类型的异常

}

private void ProcessArgs(string[] args)

{

if (args != null)

{

if (args.Length > 0)

{

foreach (string arg in args)

{

if (!string.IsNullOrEmpty(arg))

{

_ArgType |= ProcessArg(arg);

}

}

}

else

{

_ArgType = ArgType.None;

}

}

else

{

_ArgType = ArgType.None;

}

}

protected virtual ArgType ProcessArg(string arg)

{

ArgType res = ArgType.None;

// TODO:

return (res);

}

public void DoTestWork()

{

OnDoTestWork();

}

protected virtual void OnDoTestWork()

{

// TODO:

}

public void Dispose()

{

if (_License != null)

{

_License.Dispose(); // 调用_License的Dispose方法,显示释放资源

}

}

}

修改Program中的代码,以捕获LicenseException类型的异常。

class Program

{

static void Main(string[] args)

{

try

{

TestWorker testWorker = new TestWorker(args); // 实例化 TestWorker 类的实例

testWorker.DoTestWork();

}

catch (LicenseException) // 捕获到 LicenseException 类型的异常,说明许可证验证失败

{

Console.WriteLine("License Deny !"); // 告诉你一声,你没这个权限 ^_^

}

Console.Write("Press ENTER for exit");

Console.ReadLine();

}

}

[Flags]

public enum ArgType

{

None = 0,

}