You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C# Winforms如何实现登录表单每24小时仅验证一次

C# WinForm 24小时免登实现方案(服务端优先计时)

核心逻辑

优先采用服务端计时天然支持关机后时间正常累计,完全规避客户端修改本地时间绕过有效期的问题,整体实现分为服务端接口改造和客户端逻辑调整两部分。

服务端改造点

  • 原有登录接口验证账号密码通过后,生成唯一授权Token,同时记录该Token的过期时间戳=服务器当前时间戳+86400(24小时秒数),将Token、过期时间、对应用户信息存储在服务端后,把Token和过期时间返回给客户端
  • 新增Token有效性校验接口,入参为客户端上传的历史Token,返回两种状态:有效/无效,有效状态可同步返回当前绑定的用户基本信息,无效状态对应Token过期、非法或者已被销毁

客户端实现步骤

  1. 调整程序启动入口逻辑,不要直接加载登录窗体,优先执行免登校验
  2. 本地用加密方式存储历史授权Token,禁止明文存储,推荐用Windows DPAPI加密后存到系统配置文件或用户目录下的独立配置文件中
  3. 启动校验流程:
    • 第一步:读取本地存储的Token,不存在直接弹出登录窗体
    • 第二步:存在Token则调用服务端校验接口,网络异常场景可根据业务需求选择直接走登录流程,或补充本地时间校验作为降级方案
    • 第三步:接口返回Token有效,直接加载主窗体,同步传入接口返回的用户信息即可
    • 第四步:接口返回Token无效,清空本地存储的失效Token,弹出登录窗体
  4. 手动登录成功后,将接口返回的新Token加密存储到本地,直接跳转主窗体

关键代码示例

1. Token加密存储工具类

using System;
using System.Configuration;
using System.Security.Cryptography;
using System.Text;

public static class AuthStorageHelper
{
    // DPAPI加密存储Token,仅当前Windows用户可解密
    public static void SaveToken(string token)
    {
        byte[] plainText = Encoding.UTF8.GetBytes(token);
        byte[] encryptedData = ProtectedData.Protect(plainText, null, DataProtectionScope.CurrentUser);
        Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
        if (config.AppSettings.Settings["AuthToken"] == null)
            config.AppSettings.Settings.Add("AuthToken", Convert.ToBase64String(encryptedData));
        else
            config.AppSettings.Settings["AuthToken"].Value = Convert.ToBase64String(encryptedData);
        config.Save(ConfigurationSaveMode.Modified);
        ConfigurationManager.RefreshSection("appSettings");
    }

    // 读取解密Token
    public static string GetToken()
    {
        string encryptedStr = ConfigurationManager.AppSettings["AuthToken"];
        if (string.IsNullOrEmpty(encryptedStr)) return null;
        try
        {
            byte[] encryptedData = Convert.FromBase64String(encryptedStr);
            byte[] plainText = ProtectedData.Unprotect(encryptedData, null, DataProtectionScope.CurrentUser);
            return Encoding.UTF8.GetString(plainText);
        }
        catch
        {
            ClearToken();
            return null;
        }
    }

    // 清空失效Token
    public static void ClearToken()
    {
        Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
        if (config.AppSettings.Settings["AuthToken"] != null)
        {
            config.AppSettings.Settings.Remove("AuthToken");
            config.Save(ConfigurationSaveMode.Modified);
            ConfigurationManager.RefreshSection("appSettings");
        }
    }
}

2. 程序入口逻辑调整(Program.cs)

using System;
using System.Windows.Forms;

static class Program
{
    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        
        string localToken = AuthStorageHelper.GetToken();
        bool autoLoginPassed = false;

        if (!string.IsNullOrEmpty(localToken))
        {
            try
            {
                // 替换为实际的服务端校验接口调用逻辑
                var validateResult = YourApiService.ValidateToken(localToken);
                if (validateResult.IsValid)
                {
                    Application.Run(new MainForm(validateResult.UserInfo));
                    autoLoginPassed = true;
                }
                else
                {
                    AuthStorageHelper.ClearToken();
                }
            }
            catch
            {
                // 网络异常场景处理,需离线可用的话可在此补充本地时间校验逻辑
                MessageBox.Show("网络连接异常,请检查网络后重试");
            }
        }

        if (!autoLoginPassed)
        {
            LoginForm loginForm = new LoginForm();
            if (loginForm.ShowDialog() == DialogResult.OK)
            {
                AuthStorageHelper.SaveToken(loginForm.LoginResponse.Token);
                Application.Run(new MainForm(loginForm.LoginResponse.UserInfo));
            }
        }
    }
}

注意事项

  • 服务端校验优先级永远高于本地校验,不要完全依赖本地时间判断有效期
  • 服务端需定期清理过期Token,避免无效数据占用存储空间
  • 本地时间校验仅可作为无网络场景的降级方案,存在被用户修改本地时间绕过的风险

内容的提问来源于stack exchange,提问作者Custom

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 14:36:00