65.9K
CodeProject 正在变化。 阅读更多。
Home

超轻量级软件注册控件

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.86/5 (5投票s)

2012年4月10日

CPOL

5分钟阅读

viewsIcon

22299

downloadIcon

817

将此控件添加到您的应用程序中, 要求用户注册, 以便您可以收集电子邮件地址

引言

这是一个简单的 WPF 控件,可以检查已安装的应用程序是否“已注册”。如果未注册,它会提示用户输入电子邮件地址,然后将软件密钥发送给用户(以确保电子邮件地址有效),所有这些操作无需网站

背景

假设您编写了一个小应用程序,并乐意将其作为免费软件分发,但您确实想知道谁在实际使用它。您不想花时间创建一个网站并添加“真正的”注册系统的基础架构。

这是一种可以将此功能包含在您的应用程序中的方法。您完全不需要网站,并且可以收集使用您应用程序的人的电子邮件地址。该控件依赖于这样一个事实:任何计算机都可以作为电子邮件发送者,并且只要拥有凭据,就可以通过任何电子邮件帐户发送电子邮件。在此示例中,我使用的是 Gmail。

当您的用户启动应用程序时,他们会看到一个类似这样的对话框

当用户输入他的/她的电子邮件地址时,应用程序会创建密钥,并充当电子邮件客户端来生成电子邮件并将其发送给用户。用户输入密钥,应用程序会验证它是否与它内部生成的密钥匹配。如果匹配,它将存储在一个文件中(位于 users/username/AppData),这样用户就不需要重新输入密钥。

作为一项附加功能,密钥生成算法包含了包含 .exe 文件的文件夹的创建日期/时间,这很可能是应用程序的安装日期/时间。这可以防止用户共享一个电子邮件/密钥组合——每个安装都需要一个不同的密钥。

我称之为“UltraLight”,因为它为了简单而牺牲了一定的健壮性。

潜在的问题来源是 Gmail。如果来自世界各地的 Gmail 收到大量注册信息,Gmail 的反垃圾邮件发送者可能会阻止该帐户,我将不得不更改代码来解决此问题。我已经审查了 Gmail 的规则,并且不认为有任何违规行为,但您也应该在此处查看:此处; 

如果您预计会有大量注册,您应该选择一个能为您提供更好控制的电子邮件服务(可能不是免费的)。

这种方法的一个真正优势在于,由于密钥实际上是由客户端生成的,因此它可以利用客户端机器独有的数据,而无需将其发送到任何地方(这会涉及隐私问题)。在这种情况下,我使用安装日期来生成密钥,但我不会将日期发送到任何地方,只发送密钥。这意味着我可以将注册的电子邮件/密钥以明文形式存储在客户端机器上,而不会存在安全问题。

按照目前的编写方式,它是全有或全无的;未注册用户无法启动程序。通过一些小的修改,您的应用程序可以为未注册用户提供降级操作。

使用代码

为了使用源代码,您需要按照以下步骤操作。要进行尝试,只需下载并运行 .EXE 文件,并通过我的 Gmail 帐户(“SendKey3145”)将注册密钥发送给自己。

要将控件改编到您自己的应用程序

  1. 在 Gmail 上为您的应用程序创建一个电子邮件帐户。该帐户将向您的用户发送注册电子邮件。

  2. 给自己发送一封电子邮件,以确保帐户正常工作。

  3. 在程序的开头附近包含以下代码,我将其放在 MainWindow 构造函数中

    if (!RegistrationWindow.IsRegistered())
    {
        RegistrationWindow rw = new RegistrationWindow();
        if (rw.ShowDialog() != true)
        {
            this.Close();
            return;
        }
    }
  1. 如果您希望未注册用户能够“降级”操作,请不要关闭窗口,而是检查程序中的任何位置的 RegistrationWindow.IsRegistered() 来启用功能。

  2. 编辑源代码以包含 Gmail 帐户名称和密码。此外,编辑隐私声明、电子邮件正文等。

  3. 务必进行混淆!否则,您的应用程序将在明文中包含您的电子邮件帐户名称和密码,任何使用反汇编器的人都可以看到。

  4. 当用户使用您的应用程序时,它将通过 Gmail 帐户向他们发送注册密钥。

  5. 您可以随时登录 Gmail 帐户,查看已发送的注册消息,并妥善使用电子邮件地址。

关注点

如何发送邮件:使用 SmtpClient 对象来实现此功能非常简单——只需设置所有参数并调用 Send 即可。

public void SendMail(string toMail, string subject, string body)
{
    var fromAddress = new MailAddress(senderEmailAddress, senderEmailFrom);
    var toAddress = new MailAddress(toMail, toMail);
    
    var smtp = new SmtpClient
    {
        Host = "smtp.gmail.com",
        Port = 587,
        EnableSsl = true,
        DeliveryMethod = SmtpDeliveryMethod.Network,
        UseDefaultCredentials = false,
        Credentials = new NetworkCredential(fromAddress.Address, senderEmailPassword),
        Timeout = 10000
    };
    var message = new MailMessage(fromAddress, toAddress){Subject = subject,Body = 
    try
    {
        this.Cursor = Cursors.Wait;
        smtp.Send(message);
        this.Cursor = Cursors.Arrow;
        MessageBox.Show("Registration key requested.  Check your email (and junk email)  key.");
    }
    catch (Exception e)
    {
        this.Cursor = Cursors.Arrow;
        MessageBox.Show("Email request failed: " + e.Message);
    }
}

如何在 AppData 中存储/检索数据:这有点棘手,MSDN 文档含糊不清,网络上的各种答案常常相互矛盾。诀窍在于,如果您使用的是 VS 2010(我使用的是 VS Professional),右键单击项目文件并选择“属性”,然后转到“设置”选项卡,VS 会为您完成大部分工作。您需要编辑 Settings.Settings 文件(在解决方案资源管理器下的“属性”中),并添加您打算使用的密钥。如果您不这样做,如果您访问文件中不存在的密钥,程序将抛出一个无用的 XmlParser 异常。我在访问时添加了 try-catch 块。您还需要编辑“AssemblyInfo.cs”文件,并填入合理的 AssemblyCompanyAssemblyProductAssemblyVersion 值,因为这些值用于在 AppData 文件夹下创建文件文件夹。

private static void SetEmailAndKey(string email, string key)
{
    try
    {
        Properties.Settings.Default["RegistrationEmail"] = email;
        Properties.Settings.Default["RegistrationKey"] = key;
        Properties.Settings.Default.Save();
    }
    catch (Exception e)
    {
        MessageBox.Show("Failure writing app configuration file.  " + e.Message);// debug the configuration file setup
    }
}
private static void GetEmailAndKey(out string email, out string key)
{
    try
    {
        email = (string)Properties.Settings.Default["RegistrationEmail"];
        key = (string)Properties.Settings.Default["RegistrationKey"];
    }
    catch (Exception e)
    {
        email = "";
        key = "";
        MessageBox.Show("Failure reading app configuration file.  "+e.Message);// just  the configuration file setup
    }
}

如何获取文件安装日期:我认为使用文件安装日期会很有用,但在安装后,.exe 文件仍然保留其创建日期。使用包含文件夹的创建日期似乎可以解决问题,并允许用户更改版本而无需更改密钥。

static public DateTime InstallationDate
{
    get
    {
        string codeBase = System.Reflection.Assembly.GetExecutingAssembly().CodeBase;
        UriBuilder uri = new UriBuilder(codeBase);
        string path = Uri.UnescapeDataString(uri.Path);
        string directory = System.IO.Path.GetDirectoryName(path);
        return System.IO.File.GetCreationTime(directory);
    }
}

如何(不)生成软件密钥:在分发源代码的程序中进行加密没什么意义,我建议您用一个更复杂的方法替换它。重要的是要遵循软件密钥是对包含电子邮件地址和一些附加本地信息的输入字符串进行某种篡改。我传递的是电子邮件地址和安装日期/时间的连接。

string calculatedKey = CreateKey(email + InstallationDate.ToLongTimeString());
public static string CreateKey(string inputString)
{
    int i = 0;
    foreach (char c in inputString)
    {
        i += (int)c;
    }
    return i.ToString();
}

历史

初始修订:2012 年 4 月 9 日。

© . All rights reserved.