用户个人SQLite数据库的创建与管理

在本文中,将探讨如何为每个注册用户创建一个个人SQLite数据库,以及如何实现用户删除数据、下载数据库、销毁账户等增强功能。这些功能对于确保数据的可用性和所有权至关重要。

  • 用户删除单个日记条目 - 尚未完成
  • 允许用户下载整个SQLite数据库(以及用户如何本地使用它) - 已完成
  • 用户删除远程数据库和UUID - 部分完成 - 本文将解释
  • 为UUID添加二维码生成器,方便在其他设备上获取UUID和加载数据 - 已完成

此外,还添加了一个额外的增强功能,用于验证UUID是否符合预期。新的代码要求UUID值1)包含正好4个连字符,2)长度正好为36个字符(包括4个连字符)。注意到一些用户保存了像"test1"之类的UUID值。这个新增强功能有助于保护文件系统。

软件开发主题

如果要用一个短语来解释软件开发的一致主题,可能会使用:

"在理论上,实践和理论是相同的。但在实践中,它们是不同的。"

可能会稍微改变一下:

"在开发环境(localhost)中,实践和理论是相同的。但在生产环境(公共URL)中,它们是不同的。"

这是因为在开发环境中尝试的一些功能很容易实现,但在生产环境中却有所不同。"在服务器上有效!"现在,让看看实现的最简单的增强功能,并看看它的作用。

从UUID生成QRCode

为了允许用户从任何地方访问她的数据,添加了一个简单的方法,从UUID生成QRCode。用户只需点击UUID字段旁边的条形码图标按钮,就会生成一个QRCode。

是的,可以采取以下步骤来写入UUID数据库:

  1. 将设备相机对准本文中的图像
  2. 从QRCode中获取UUID
  3. 转到 https://newlibre.com/journal
  4. 将UUID粘贴到UUID文本框中
  5. 点击[Gen/Set UUID]
  6. 查看插入到该数据库中的条目
  7. 向该数据库副本添加新条目
  8. 下载这个特定数据库的副本(稍后会有更多内容)

UUID:"快速登录"。由于没有人会猜测UUID,使用UUID登录用户。

是的,如果有人黑客攻击网站,他们将看到所有UUID文件夹,并能够访问任何SQLite数据库。是的,这并不安全。是的,这是一个原型,将向展示如何解决这个问题。

用户只需点击页面上的链接即可下载他们的SQLite数据库副本。它将下载到Web浏览器的下载目录。就这么简单。但是,背后的WebAPI(C#)和JavaScript并不那么简单,让看看。

[HttpPost] public ActionResult DownloadSqliteDb([FromQuery] String uuid) { var userDir = Path.Combine(webRootPath, uuid); var journalDb = Path.Combine(userDir, templateDbFile); Console.WriteLine(journalDb); return new PhysicalFileResult(journalDb, "application/x-sqlite3"); }

用户必须传递UUID以识别她尝试下载的数据库。然后只需创建用户文件空间路径到sqlite db(记住从第一篇文章中,模板SQLite数据库被命名为sqlstone_journal.db)。

然后发现了必须使用PhysicalFileResult()来正确返回文件的字节。如果尝试返回FileResult(),会发生一件非常奇怪的事情。那件奇怪的事情发生在身上,几乎要咬断手臂来修复这个问题。然后最终发现了一些文档,并在博客上写了出来。

需要JavaScript来处理PhysicalFileResult

当文件返回时,决定想用一个包含简单时间戳的名称来保存它,这样下载的浏览器就不会只是将其命名为file(1).db,file(2).db等。此外,这意味着如果有多个UUID日记,可以下载它们而不会覆盖它们。

function downloadSqliteDb() { console.log("1"); if (currentUuid != null) { fetch(`${baseUrl}User/DownloadSqliteDb?uuid=${currentUuid}`, { method: 'POST', }) .then(resp => { console.log(resp); return resp.blob(); }) .then(blob => { downloadFile(blob, `journal-${GetFileTimeFormat(new Date())}.db`); }); } else { uuidRegisterAlert("You need to register your UUID to be able to download your sqlite data. Please register your UUID & try again.", true); } }

如所见,还调用了另一个JS函数GetFileTimeFormat(),用它来用时间戳命名文件。会让在源代码中查看那段代码。

有趣的代码是downloadFile() JavaScript。它很奇怪,但它有效。

function downloadFile(blob, name = "journal.db") { const href = URL.createObjectURL(blob); const a = Object.assign(document.createElement("a"), { href, style: "display:none", download: name, }); document.body.appendChild(a); a.click(); URL.revokeObjectURL(href); a.remove(); }

疯狂的事情。

这里还有另一个功能要讨论。想让用户能够销毁她的账户。这样她就可以拥有自己的数据。

销毁账户及关联的SQLite数据库

无权评判?如果想删除日记数据,很乐意让这么做。

[HttpPost] public ActionResult DestroyUserAccount([FromQuery] String uuid) { // Every valid UUID will have 4 hyphens & be 36 chars long int hyphenCounter = uuid.AsSpan().Count('-'); if (uuid.Length != 36 || hyphenCounter != 4) { return new JsonResult(new { result = false, message = "Your uuid doesn't look like a valid value.\nCannot delete account." }); } var userDir = Path.Combine(webRootPath, uuid); try { Directory.Delete(userDir, true); } catch (Exception ex) { return new JsonResult(new { result = false, message = $"Error! Delete Failed. \nCannot delete account. {ex.Message}" }); } return new JsonResult(new { result = true, message = "The user account and all associated data has been destroyed." }); }

发布UUID,在做了一些检查以确保它看起来像一个有效的ID之后,WebAPI将调用Directory.Delete(),带有true参数(表示应该销毁所有文件夹和文件)。

UUID的验证

发现需要这样做,否则一些聪明人会过来,使他的UUID成为css或其他文件夹名称,然后删除Web文件夹。哈哈!那不是很有趣吗?不!

所以检查UUID是否有4个连字符,并且正好是36个字符。如果两个测试都失败了,就拒绝用户的发布。拒绝和一切!😁

function destroyAccount() { fetch(`${baseUrl}User/DestroyUserAccount?uuid=${currentUuid}`, { method: 'POST', }) .then(response => response.json()) .then(data => { if (data.result == false) { alert(`Could not destroy the account. \nError -> ${data.message}`); return; } uuidRegisterAlert("The UUID, User Account & all associated data was permanently deleted."); localStorage.removeItem("currentUuid"); currentUuid = null; document.querySelector("#uuid").value = ""; window.location.reload(); }); document.querySelector("#modalCloseBtn").click(); }

删除账户的问题

这一切都在本地主机上运行得很好。删除每次都成功。

但是当把代码移到产品服务器(https://newlibre.com/journal)时,开始得到一个500错误。

完全困惑,直到在API调用中放入一个try/catch。一旦这样做了,发现删除Sqlite DB时有一个错误,因为服务认为Sqlite DB有一个连接打开。由于它认为文件正在使用中,它不允许删除Sqlite db并删除目录。

兔子洞:EF Core,Sqlite DB连接等。

现在要跳进兔子洞,试图发现一种方法来强制应用程序关闭连接,但是那里有很多技术正在进行,可能很难发现谁在保持连接打开。

唉,这就是软件开发人员的生活。

点击垃圾桶图标(下图中突出显示),一个警告对话框会弹出。

如果想销毁账户,点击[Destroy Account]按钮。

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485