feat: 实现密码加密存储与异步数据预览功能
- 在 Config.cs 中添加 DPAPI 加密支持,确保密码安全存储,兼容旧版配置。 - 更新 MainForm.cs,重构数据预览逻辑为异步方法,提升用户体验,避免界面冻结。 - 修改相关方法以支持异步操作,确保在处理大文件时界面响应流畅。 - 更新项目文件以引用 System.Security,支持加密功能。
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace TfsExcelImporter
|
||||
@@ -20,8 +22,43 @@ namespace TfsExcelImporter
|
||||
|
||||
// 认证固定 NTLM:用户名可写 user,也可写 DOMAIN\user
|
||||
public string Username { get; set; } = "";
|
||||
|
||||
// 明文密码只存在于内存(UI 回显需要);落盘一律走 DPAPI 加密的 PasswordEnc。
|
||||
// [JsonIgnore] 防止明文随 SerializeObject 写进 config.json。
|
||||
[JsonIgnore]
|
||||
public string Password { get; set; } = "";
|
||||
|
||||
// 兼容旧版明文键:反序列化时承接旧 config.json 的 "Password",下次 Save 自动转为加密存储。
|
||||
// getter 恒返 null,序列化不再输出明文键。
|
||||
[JsonProperty("Password", NullValueHandling = NullValueHandling.Ignore)]
|
||||
private string LegacyPassword { get { return null; } set { if (!string.IsNullOrEmpty(value)) Password = value; } }
|
||||
|
||||
// DPAPI(CurrentUser) 加密后的密码,Base64;同机同用户可解,拷到别的机器/账户需重输。
|
||||
[JsonProperty("PasswordEnc", NullValueHandling = NullValueHandling.Ignore)]
|
||||
private string PasswordEnc { get; set; } = "";
|
||||
|
||||
// ------------------------------------------------------------- DPAPI
|
||||
|
||||
private static string Protect(string plain)
|
||||
{
|
||||
var bytes = ProtectedData.Protect(Encoding.UTF8.GetBytes(plain), null, DataProtectionScope.CurrentUser);
|
||||
return Convert.ToBase64String(bytes);
|
||||
}
|
||||
|
||||
/// <summary>解密失败返回 null(不抛异常,让调用方回退到空密码)。</summary>
|
||||
private static string TryUnprotect(string cipher)
|
||||
{
|
||||
try
|
||||
{
|
||||
var bytes = ProtectedData.Unprotect(Convert.FromBase64String(cipher), null, DataProtectionScope.CurrentUser);
|
||||
return Encoding.UTF8.GetString(bytes);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// 旧版本有 BypassRules 开关,已移除:TFS 2013 对应的 Client OM 14.x 没有 SaveFlags.BypassRules
|
||||
// (15.x 才加,而 15.x 不兼容 TFS 2013),勾选从未生效。旧 config.json 里的残留键由
|
||||
// Newtonsoft 按默认 MissingMemberHandling.Ignore 忽略,不需要手工清理。
|
||||
@@ -80,7 +117,16 @@ namespace TfsExcelImporter
|
||||
if (File.Exists(ConfigPath))
|
||||
{
|
||||
var cfg = JsonConvert.DeserializeObject<AppConfig>(File.ReadAllText(ConfigPath));
|
||||
if (cfg != null) return cfg;
|
||||
if (cfg != null)
|
||||
{
|
||||
// 加密值优先于旧明文键;解密失败(换机/换账户/文件被改)留空,用户重输即可
|
||||
if (!string.IsNullOrEmpty(cfg.PasswordEnc))
|
||||
{
|
||||
var plain = TryUnprotect(cfg.PasswordEnc);
|
||||
if (plain != null) cfg.Password = plain;
|
||||
}
|
||||
return cfg;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -92,6 +138,8 @@ namespace TfsExcelImporter
|
||||
|
||||
public void Save()
|
||||
{
|
||||
// 落盘前把内存中的明文加密;Password 本身带 [JsonIgnore] 不会写出
|
||||
PasswordEnc = string.IsNullOrEmpty(Password) ? "" : Protect(Password);
|
||||
var json = JsonConvert.SerializeObject(this, Formatting.Indented);
|
||||
try
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user