.NET Framework给应用程序颁发许可证(下)

_ by Kenn Scribner

翻译:邹建强 _

注册表许可证提供者

正如我前面所提到的,大多数许可证的校验工作是由你的许可证提供者的 GetLicense() 方法去做的。这里有些代码,是为我自己的注册表许可证提供者写的(你可以在 RegistryLicenseProvider.cs 这个源文件示例中找到):

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


   // We'll test for the usage mode...run time v. design time.  
   // Note we only check if run time...  
   if (context.UsageMode == LicenseUsageMode.Runtime)   
   {  
      // The Registry key we'll check  
      RegistryKey licenseKey =   
    Registry.CurrentUser.OpenSubKey("Software\\Acme\\HostKeys");  



      if ( licenseKey != null )   
      {  
         // Passed the first test, which is the existence of the  
         // Registry key itself. Now obtain the stored value  
         // associated with our app's GUID.  
         string strLic =  
(string)licenseKey.GetValue(type.GUID.ToString()); // reflected!  
         if ( strLic != null )   
         {  
            // Passed the second test, which is some value  
            // exists that's associated with our app's GUID.  
            if ( String.Compare("Installed",strLic,false) == 0 )  
            {  
               // Got it...valid license...  
               return new RuntimeRegistryLicense(type);  
            } // if  
         } // if  
      } // if 


      // if we got this far, we failed the license test. We then  
      // check to see if exceptions are allowed, and if so, throw  
      // a new license exception...


      if ( allowExceptions == true )   
      {  
         throw new LicenseException(type,   
                                    instance,   
                                    "Your license is invalid");  
      } // if 


      // Exceptions are not desired, so we'll simply return null.  
      return null;  
   } // if  
   else   
   {  
      return new DesigntimeRegistryLicense(type);  
   } // else  
}

下面这部分检查代码比较令人感兴趣,我们可以检查当前运行在什么模式下,是设计时还是运行时:

if (context.UsageMode == LicenseUsageMode.Runtime)   
{  
   ... // Run time mode  
}  
else   
{  
   ... // Design time mode  
} // else

如果在设计时操作,我们会简单地创建并返回一个我们设计时许可证对象的实例:

return new DesigntimeRegistryLicense(type);

然而如果是运行时,我们可以打开我们特殊的注册键值去寻找我们应用程序的GUID键值对。我们如下方式打开注册表键:

RegistryKey licenseKey =  
Registry.CurrentUser.OpenSubKey("Software\\Acme\\HostKeys");

通过反射应用程序GUID,我们生成这个键值。这个GUID来自于我们得到的对象(还记得放在我们许可证类型的 GuidAttribute 属性吧):

string strLic =   
   (string)licenseKey.GetValue(type.GUID.ToString());

GetValue() 方法不是返回与这个键相关联的值就是返回null,因此我们对null值测试,对我们期望返回的值进行检查看是不是代表一个合法的许可证:

if ( strLic != null )  
{  
   // Passed the second test, which is some value  
   // exists that's associated with our app's GUID.  
   if ( String.Compare("Installed",strLic,false) == 0 )  
   {  
      // Got it...valid license...  
      return new RuntimeRegistryLicense(type);  
   } // if  
} // if

如果一切正常,我们会返回我们运行时许可证对象的一个新实例。否则我们会检查是否允许异常,如果是就抛出一个新许可证异常:

if ( allowExceptions == true )
{
throw new LicenseException(type,
instance,
"Your license is invalid");
} // if

如异常不被允许,我们就简单的返回null。

这种情形下许可证类是一样的,但是相同不是必需的。运行时许可证如下显示:

public class RuntimeRegistryLicense : License   
{  
   private Type type; 


   public RuntimeRegistryLicense(Type type)   
   {  
      if ( type == null )   
         throw new NullReferenceException(  
"The licensed type reference may not be null.");  
      this.type = type;  
   } 


   public override string LicenseKey   
   {  
      get   
      {  
         // Simply return the application's GUID  
         return type.GUID.ToString();  
      }  
   }  
   public override void Dispose()   
   {  
   }  
}

由于从基类 License 派生了一个新的许可证类型,我必须重载这个 LicenseKey 属性(它是abstract方法)。当被要求时,会返回应用程序的GUID。不管怎样,我可以重新得到注册表值或者对定期的失效和别的某些非法条件做检查。

更多的其它许可证方案

我在这里演示的技巧相当基础。但是一方面许多用户在没有大量帮助的情况下不能打开注册表找到键值,另一方面有些人有相当的能力去破解这个方案。因此,你要做的就是要让你的许可证方案更难破解。

你所要做的最明显的事就是用一个产品有效期数据来替换我的简单的“Installed”字串(并且对这个值加密)。或者你写一个更复杂的许可证提供者,让它调用Windows或Web服务向它们申请一个执行应用程序的许可。这两种方式我都写过非常有效。正如我提过的,许可证对象自身可以使自己无效,迫使应用程序关闭,它得到的只是些无效的证书。或许可以从Web服务或数据库中检查的许可证来决定这个应用程序日常的许可证状态。无论在何种情况下,你要确保把你产品汇编后结果做混淆处理!

结论

如果你已经阅读到了这里并且研究了基本的框加许可过程,你可能奇怪:为什么我写了这么多东西都是局限于这个框架(.NET Framework)内的呢?我们难首不能创建一个自己的许可证管理器吗?为什么没有一个非框架的许可证构架呢?只要把一个布尔值传线 GetLicense() 方法启用异常呢?(我个人希望是指定给 LicenseManger 或许可证类一个属性而不是把一个布尔值传给 GetLicense() …… 我还没看见过有任何别的方式能改变默认框架行为)

我仅能假设使用框架的许可证架构而不是你自己的这会对你的将来开发更有利。毕竟你要遵循框架规定的模式,改变框架可能会对你造成一定的影响。因为你肯定要利用一些框架提供的组件,重用这些资源可以节省(尽管少)你维护的开销。

就许可证自身而言,唯一的限制是你自己的想象力。现在就去赚回你损失的钱吧!

源代码下载

源代码下载: LicensedApps.zip - 76 kb

About the Author...

** Kenn Scribner ** finds himself consulting and helping other developers understand the complexities of Windows and COM programming. Kenn considers himself fortunate to pursue his hobby as a career and enjoys sharing his experiences with other developers. To that end, Kenn has written four books: MFC Programming with Visual C++ 6 Unleashed , Teach Yourself ATL in 21 Days , Understanding SOAP , and his newest, Applied SOAP: Implementing .NET Web Services . He has contributed to several other books, including Mike Blasczak's Professional MFC with Visual C++ 6. Kenn has also contributed numerous XML and SOAP articles to Visual C++ Developer, which you can find (along with many products and code samples) at his personal Web site, EnduraSoft.

Published At
Categories with Web编程
Tagged with
comments powered by Disqus