[转],NET的许可证机制 ---- 转自: http://hi.baidu.com/gsgaoshuang/item/ef42683b93a7f7c3392ffade http://www.cnblogs.com/trampt/archive/2011/04/01/2002243.ht
主要类:
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基于文本文件的许可证机制。
简单应用:
1:首先要创建一个License,但是因为License是抽象的,所以要创建一个集成自License的子类,实现License的一些方法。
2:创建一个LicenseProvider类,这个类要集成LicenseProvider的类。实现一些方法。LicenseProvider类提供了验证机制的程序。LicenseProvider类要重载GetLicense(LicenseContext,Type ,object ,bool)方法,该方法真正提供了,一些算法,去实现验证。
3:创建一个自定义的类,并且给该类添加LicenseProviderAttribute属性。指定对这个类进行验证的机制采用LiceseProvider。
具体代码:
定义Licese类
private class MyLicense : License
{
private String mLicenseKey = null;
private MyLicenseProvider mProvider = null;
public MyLicense(MyLicenseProvider provider, String key)
{
this.mProvider = provider;
this.mLicenseKey = key;
}
public override string LicenseKey
{
get { return this.mLicenseKey; }
}
public override void Dispose()
{
this.mProvider = null;
this.mLicenseKey = null;
}
}
定义LicenseProvider类
[ReflectionPermission(SecurityAction.Deny, MemberAccess=false, ReflectionEmit=false)]
internal class MyLicenseProvider : LicenseProvider
{
构造函数
public MyLicenseProvider()
{ }
/// <summary>
/// 获取本机MAC地址 其实这个不管是获取本机硬件参数的任何信息都可以这要能标志该机器即可
/// </summary>
private String GetMacAddress()
{
String macAddr = null;
ManagementClass inetAdapter = new ManagementClass("WIN32_NetworkAdapterConfiguration");
ManagementObjectCollection objList = inetAdapter.GetInstances();
foreach (ManagementObject mobj in objList)
{
if ((bool)mobj["IPEnabled"])
{
macAddr = mobj["MacAddress"].ToString().Replace(":", "-");
break;
}
}
return macAddr;
}
/// <summary>
/// 获取Assembly所在目录 获取应用程序所在的目录
/// </summary>
private String GetAssemblyPath(LicenseContext context)
{
String fileName = null;
Type type = this.GetType();
ITypeResolutionService service = (ITypeResolutionService)context.GetService(typeof(ITypeResolutionService));
if (service != null)
{
fileName = service.GetPathOfAssembly(type.Assembly.GetName());
}
if (fileName == null)
{
fileName = type.Module.FullyQualifiedName;
}
return Path.GetDirectoryName(fileName);
}
private String Encrypt(String source) 加密算法,可以用,也可不用,这里为了更安全,就用。
{
/**
* 加密算法
*/
byte[] keyData = Encoding.ASCII.GetBytes("");
byte[] ivData = Encoding.ASCII.GetBytes("4iJ9Qw#L");
MemoryStream stream = new MemoryStream();
DES desProvider = new DESCryptoServiceProvider();
CryptoStream cs = new CryptoStream(stream,
desProvider.CreateEncryptor(keyData, ivData),
CryptoStreamMode.Write);
byte[] buffer = Encoding.ASCII.GetBytes(source);
cs.Write(buffer, 0, buffer.Length);
cs.FlushFinalBlock();
cs.Close();
buffer = stream.GetBuffer();
stream.Close();
return Convert.ToBase64String(buffer);
return source;
}
public override License GetLicense(LicenseContext context, Type type, object instance, bool allowExceptions)
{
MyLicense license = null;
// 计算MAC地址加密串
String macAddr = this.GetMacAddress();
String encrypt = this.Encrypt(macAddr);
if (context != null)
{
if (context.UsageMode == LicenseUsageMode.Runtime)
{
String savedLicenseKey = context.GetSavedLicenseKey(type, null);
if (encrypt.Equals(savedLicenseKey))
{
return new MyLicense(this, encrypt);
}
}
if (license != null)
{
return license;
}
// 打开License文件 'license.dat'
String path = this.GetAssemblyPath(context);
String licFile = Path.Combine(path, "license.dat");
if (File.Exists(licFile))
{
Stream fs = new FileStream(licFile, FileMode.Open, FileAccess.Read);
StreamReader sr = new StreamReader(fs);
String readedLicenseKey = sr.ReadToEnd();
sr.Close();
fs.Close();
if (encrypt.Equals(readedLicenseKey))
{
license = new MyLicense(this, encrypt);
}
}
if (license != null)
{
context.SetSavedLicenseKey(type, encrypt);
}
}
if (license == null)
{
System.Windows.Forms.MessageBox.Show("!!!尚未注册!!!");
return new MyLicense(this, "evaluate");
}
return license;
}
指定该类进行许可验证的程序采用MyLicenseProvider 这句必须的。
[LicenseProvider(typeof(MyLicenseProvider))]
public partial class LicenseHelper
{
private License mLicense = null;
public LicenseHelper()
{
this.mLicense = LicenseManager.Validate(typeof( LicenseHelper), this);
}
~ LicenseHelper() 析构函数,在C#中,不常用。
{
if (this.mLicense != null)
{
this.mLicense.Dispose();
this.mLicense = null;
}
}
}
这样。在程序中调用LicenseHelper是就要进行验证,否则。就会出现异常。
该方法也可以对软件进行加密,只是在GetLicense(LicenseContext, type, object,bool);方法中写的机密算法要复杂一些。但是道理都是这样的。
==========================================
实验环境: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, } |
浙公网安备 33010602011771号