Skip to content

C# 软件授权最佳实践

面向 C# / .NET 桌面软件(WinForms / WPF) 的授权落地建议。代码片段基于 C# SDK

一、登录流程(异步)

界面启动即异步登录,避免阻塞 UI 线程:

csharp
public async Task<bool> TryLoginAsync(string card, string mac)
{
    var client = new A7Client("150018", "YOUR_APP_KEY");
    try
    {
        var resp = await client.CallAsync("SingleLogin", new Dictionary<string, string>
        {
            ["Card"] = card, ["Mac"] = mac, ["DeviceName"] = Environment.MachineName
        });
        if (resp.GetProperty("code").GetInt32() == 200)
        {
            _token = resp.GetProperty("data").GetProperty("token").GetString();
            _loginType = "card";
            StartHeartbeat(client);
            return true;
        }
        ShowError(resp.GetProperty("message").GetString());
        return false;
    }
    catch (Exception ex)
    {
        ShowError("网络异常:" + ex.Message);
        return false;
    }
}

二、心跳线程

登录成功后启动一个 Task 每 5 分钟心跳:

csharp
private void StartHeartbeat(A7Client client)
{
    _ = Task.Run(async () =>
    {
        while (_token != null)
        {
            var hb = await client.CallAsync("UserHeartbeat", new Dictionary<string, string>
            {
                ["Token"] = _token, ["Type"] = _loginType
            });
            int code = hb.GetProperty("code").GetInt32();
            if (code is 1005 or 1006 or 1007)
            {
                _token = null;
                OnSessionExpired();
                break;
            }
            if (hb.GetProperty("data").TryGetProperty("msg", out var m) && m.GetString() is { Length: > 0 } msg)
                ShowBulletin(msg);
            await Task.Delay(TimeSpan.FromMinutes(5));
        }
    });
}

三、换绑检测

用户换电脑登录时 UserLogin 返回 1022,引导调用 ChangeBind

csharp
if (code == 1022)
{
    var old = resp.GetProperty("data").GetProperty("remark").GetString();
    if (MessageBox.Show($"检测到更换设备(原 {old}),是否换绑?", "换绑",
        MessageBoxButtons.YesNo) == DialogResult.Yes)
    {
        await client.CallAsync("ChangeBind", new Dictionary<string, string>
        {
            ["UserName"] = user, ["Password"] = pwd, ["Mac"] = DeviceId.Get()
        });
    }
}

四、AppId / AppKey 安全

不要把 AppKey 明文写进代码

AppKey 只在 Init 阶段使用一次。建议:

  • 用资源文件 + 轻量混淆,或
  • 登录时由你的下发服务临时提供,避免被逆向直接提取。

ApiPassword 仅存内存(SDK 已如此实现),不要写入 app.config 或注册表。

五、离线宽限

断网时按 离线授权与宽限期 给 30 分钟宽限,期间允许使用,网络恢复后立即补心跳。

六、机器码

参考 设备指纹与硬件绑定 的 C# 实现采集 DeviceId,在 SingleLogin / UserLogin / ChangeBind 中统一传入。

相关链接

A7验证 · 软件授权与网络验证平台