精品熟人妻一区二区三区四区不卡-精品爽黄69天堂a-精品水蜜桃久久久久久久-精品丝袜国产自在线拍-精品丝袜国产自在线拍a-精品丝袜国产自在线拍免费看

LOGO OA教程 ERP教程 模切知識(shí)交流 PMS教程 CRM教程 開發(fā)文檔 其他文檔  
 
網(wǎng)站管理員

軟件離線授權(quán)碼設(shè)計(jì)思路

admin
2025年3月24日 22:33 本文熱度 467

離線授權(quán)碼設(shè)計(jì)

對(duì)于自己的軟件產(chǎn)品,希望別人付費(fèi)、或者在我們授權(quán)的情況下才允許使用。那么我們應(yīng)該如何去這個(gè)授權(quán)碼 / 許可證的機(jī)制呢?

前言

離線授權(quán)的方案無(wú)非就是兩種,一種是軟件層面的授權(quán),一種是硬件層面的授權(quán)。

軟件層面:我們向用戶提供一串特定的字符串,用戶在軟件中輸入我們提供的字符串,在使用端校驗(yàn)用戶輸入的授權(quán)碼,即可完成軟件的授權(quán)操作。

硬件層面:我們向用戶提供一個(gè) USB Key(加密狗),用戶在運(yùn)行軟件時(shí)我們可以通過(guò)硬件加密狗來(lái)判斷授權(quán)信息,這種加密狗在網(wǎng)上 幾塊錢到十幾塊錢就能買一個(gè),有的加密狗還內(nèi)置獨(dú)立時(shí)鐘,可以杜絕用戶進(jìn)行時(shí)鐘回?fù)艿取_@種加密狗可以用在對(duì)授權(quán)安全級(jí)別更高的場(chǎng)景中,但需要承受額外的成本:用戶的使用成本,授權(quán)分發(fā)成本(加密狗+快遞費(fèi)+快遞時(shí)間)。

軟件層面的加密方案使用起來(lái)更加靈活,硬件層面加密狗安全級(jí)別更高,本篇文章主要是探討軟件層面的授權(quán)方式。

授權(quán)碼要點(diǎn)

那么設(shè)計(jì)一個(gè)相對(duì)安全的離線授權(quán)碼,需要滿足那些哪些特征呢?

  • ? 綁定性:每個(gè)授權(quán)碼對(duì)應(yīng)一臺(tái)設(shè)備的授權(quán),客戶無(wú)法通過(guò)一個(gè)授權(quán)碼激活多臺(tái)設(shè)備。
  • ? 安全性:授權(quán)碼應(yīng)難以被偽造或篡改
  • ? 可驗(yàn)證:授權(quán)碼應(yīng)能被系統(tǒng)快速驗(yàn)證其合法性
  • ? 可復(fù)現(xiàn):當(dāng)客戶授權(quán)碼遺失時(shí),我們可以根據(jù)客戶的機(jī)器碼重新生成授權(quán)碼,避免用戶無(wú)法使用軟件的情況。
  • ? 時(shí)效性(可選):授權(quán)碼可包含授權(quán)有效期,限定授權(quán)使用時(shí)長(zhǎng)。
  • ? 可擴(kuò)展(可選):可根據(jù)自己需求來(lái)靈活擴(kuò)展授權(quán)碼內(nèi)容,以方便攜帶更多信息。

你可以以任何形式生成一個(gè)滿足上方條件的授權(quán)碼,無(wú)需糾結(jié)生成的思路是否與我的思路一致

唯一標(biāo)識(shí)

在離線授權(quán)場(chǎng)景中,我們需要確定授權(quán)設(shè)備的唯一標(biāo)識(shí),這個(gè)標(biāo)識(shí)需要具有不可更改性質(zhì),在正常情況下該唯一標(biāo)識(shí)都不會(huì)發(fā)生變化(例如重啟軟件、重啟系統(tǒng)不會(huì)發(fā)生變化,但重裝系統(tǒng)、更換硬件等行為會(huì)發(fā)生變化是可接受的)。

在這種場(chǎng)景中,我們唯一標(biāo)識(shí)一般采用 CPUID、主板 BIOS UUID、網(wǎng)卡 MAC 地址、或自定義算法來(lái)生成唯一ID,提醒一下 如果產(chǎn)品是服務(wù)器應(yīng)用,不應(yīng)使用 硬盤序列號(hào)作為唯一標(biāo)識(shí)的組成部分,因?yàn)榉?wù)器硬盤都有明確的生命周期會(huì)定期更換。當(dāng)更換后就會(huì)造成授權(quán)失效的情況。

這個(gè)唯一標(biāo)識(shí)沒(méi)有明確的授權(quán)規(guī)定,大家可以根據(jù)自己的需求來(lái)選擇,也可以通過(guò)現(xiàn)成的開源庫(kù)來(lái)獲取。

例如我開發(fā)的主語(yǔ)言是 Golang,我一般會(huì)使用 github.com/denisbrodbeck/machineid 這個(gè)庫(kù)來(lái)獲取硬件ID,并且可以在各個(gè)系統(tǒng)下運(yùn)轉(zhuǎn)良好。

授權(quán)碼方案

對(duì)稱方案

對(duì)稱方案是指授權(quán)碼的生成邏輯、校驗(yàn)邏輯完全一樣。所謂校驗(yàn)就是客戶端內(nèi)部生成正確的授權(quán)碼,然后和用戶輸入的授權(quán)碼做對(duì)比,對(duì)比成功,則說(shuō)明授權(quán)有效。

以我個(gè)人習(xí)慣為例,授權(quán)碼的字符串一般包含“機(jī)器碼”、“項(xiàng)目名稱”、“到期時(shí)間”、“鹽值”,其中鹽值用于增加授權(quán)碼的復(fù)雜性,即使客戶知道了授權(quán)碼的生成方式,在不知道鹽值的情況下,無(wú)法自行偽造授權(quán)碼。

生成過(guò)程

我們先生成一個(gè)明文的字符串,然后通過(guò)特定分隔符拼接出明文的授權(quán)碼,格式可以是: 機(jī)器碼:項(xiàng)目名稱:到期時(shí)間:鹽值,例如:

123456:tpamis:281231:abcdef

  • 123456:客戶提供的機(jī)器碼,這里以 123456 代替
  • tpamis:授權(quán)項(xiàng)目名稱,同一個(gè)機(jī)器上可能存在多個(gè)軟件產(chǎn)品,可以加一個(gè)項(xiàng)目名稱用于區(qū)分。
  • 281231:到期時(shí)間,這里取 2028-12-31 的后6位作為到期時(shí)間。這里也可以寫成授權(quán)天數(shù),先選定一個(gè)時(shí)間作為起始日期,然后在這個(gè)時(shí)間上疊加偏移時(shí)間,得到的最終時(shí)間作為授權(quán)到期時(shí)間。例如:我出生的時(shí)間是:1998-11-11,我以此作為起始時(shí)間。偏移時(shí)間:9628 天,得到授權(quán)到期時(shí)間為 2028-12-31
  • abcdef:鹽值,可以防止彩虹表攻擊,即使攻擊者知道生成算法,也無(wú)法通過(guò)預(yù)計(jì)算破解授權(quán)碼。

接著,我們通過(guò)一個(gè) MD5 算法(也可使用其他 HASH 摘要算法)得到一個(gè)簽名 "cfb9fc32230fa1a19423ef8b6af63a61",此簽名就是一個(gè)授權(quán)碼。

但這時(shí)的授權(quán)碼有一個(gè)問(wèn)題,簽名是不可逆的,所以我們無(wú)法在驗(yàn)證簽名時(shí)通過(guò)簽名得到授權(quán)到期時(shí)間,所以我們需要人為的拼接一下:

  • ? 直接拼接: cfb9fc32230fa1a19423ef8b6af63a61281231
  • ? 使用分隔字符: cfb9fc32230fa1a19423ef8b6af63a61-281231
  • ? 舍去后六位,以 UUID 的方式呈現(xiàn): cfb9fc32-230f-a1a1-9423-ef8b6a281231

掩藏到期時(shí)間

這個(gè)時(shí)你會(huì)發(fā)現(xiàn) 后六位明晃晃的擺在那里,太容易被人猜到是到期時(shí)間了,雖然不會(huì)被篡改,但仍希望隱藏在授權(quán)碼中,我們可以通過(guò) 十進(jìn)制轉(zhuǎn)十六進(jìn)制來(lái)實(shí)現(xiàn):281231 轉(zhuǎn)十六進(jìn)制為:44a8f,這時(shí)授權(quán)碼變成:cfb9fc32-230f-a1a1-9423-ef8b6a44a8f

同時(shí)你可以將到期時(shí)間藏在授權(quán)碼中間,替換掉對(duì)應(yīng)位置的簽名值,得到這樣的授權(quán)碼:cf44a8f2-230f-a1a1-9423ef8b6af63a61

驗(yàn)證授權(quán)碼

到這一步,已經(jīng)完成了授權(quán)碼的生成過(guò)程,客戶端程序需要提前內(nèi)置鹽值和同樣的生成算法,在用戶輸入授權(quán)碼激活時(shí),先從授權(quán)碼中截取出到期時(shí)間。再用客戶端生成的授權(quán)碼進(jìn)行對(duì)比驗(yàn)證是否正確,以及是否過(guò)期。

用戶體驗(yàn)優(yōu)化

簽名生成的授權(quán)碼以及可以滿足正常的離線授權(quán)的功能了,但有一些不允許插入U(xiǎn)盤或聯(lián)網(wǎng)的場(chǎng)景中,客戶可能需要手動(dòng)輸入授權(quán)碼,我們應(yīng)該盡可能縮短授權(quán)碼長(zhǎng)度,方便用戶輸入。

我們可以在前面授權(quán)碼的基礎(chǔ)上,參考 Windows 的授權(quán)碼長(zhǎng)度 (AAAAA-BBBBB-CCCCC-DDDD-EEEEE),每組5個(gè)字符,5 組共25個(gè)字符,通過(guò)橫杠分割方便用戶輸入。

前面 MD5 生成的簽名是 128 位的二進(jìn)制,轉(zhuǎn)換為16進(jìn)制后,長(zhǎng)度為 32 個(gè)字符。其實(shí)我們可以 MD5 轉(zhuǎn)為 36 進(jìn)制得到: CAQ3DFUC0YPEHDZLA7ZKHHYLD

我們?cè)倨唇由锨懊娴玫降氖M(jìn)制到期時(shí)間,并轉(zhuǎn)為全大寫,就得到了方便輸入的授權(quán)碼格式:CAQ3D-FUC0Y-PEHDZ-LA7ZK-HHYLD-44A8F

如果需要長(zhǎng)度和 Windows 一模一樣,則需要在 36 進(jìn)制轉(zhuǎn)換后,再截取掉 5 位,拼接時(shí)間戳。

這里提供一個(gè) Go 語(yǔ)言 十六進(jìn)制轉(zhuǎn)36進(jìn)制的方法示例:

package main

import (
    "crypto/md5"
    "encoding/hex"
    "fmt"
    "math/big"
)

// 將 MD5 哈希值轉(zhuǎn)換為 36 進(jìn)制字符串
func md5ToBase36(md5Hash string) string {
    // 將 MD5 哈希值(十六進(jìn)制)轉(zhuǎn)換為大整數(shù)
    bigInt := new(big.Int)
    bigInt.SetString(md5Hash, 16)

    // 定義 36 進(jìn)制的字符集
    const charset = "0123456789abcdefghijklmnopqrstuvwxyz"

    // 將大整數(shù)轉(zhuǎn)換為 36 進(jìn)制
    base36 := ""
    base := big.NewInt(36)
    zero := big.NewInt(0)
    remainder := new(big.Int)

    for bigInt.Cmp(zero) > 0 {
        bigInt.DivMod(bigInt, base, remainder)
        base36 = string(charset[remainder.Int64()]) + base36
    }

    return base36
}

func main() {
    // 計(jì)算字符串的 MD5 哈希值
    data := "123456:tpamis:281231:abcdef"
    hash := md5.Sum([]byte(data))
    md5Hash := hex.EncodeToString(hash[:]) // 轉(zhuǎn)換為十六進(jìn)制字符串

    fmt.Println("MD5 哈希值:", md5Hash) // 輸出: cfb9fc32230fa1a19423ef8b6af63a61

    // 將 MD5 哈希值轉(zhuǎn)換為 36 進(jìn)制
    base36Code := md5ToBase36(md5Hash)
    fmt.Println("36 進(jìn)制編碼:", base36Code) // 輸出: caq3dfuc0ypehdzla7zkhhyld
}

幾個(gè)問(wèn)題補(bǔ)充

為什么要轉(zhuǎn) 36進(jìn)制而不是直接截取 MD5?

因?yàn)榻厝『筮^(guò)短的 MD5 增加了碰撞的概率,轉(zhuǎn)為 36進(jìn)制,會(huì)包含 0-9、A-Z 36 個(gè)字符。36進(jìn)制相比 16進(jìn)制更為緊湊,在縮短長(zhǎng)度同時(shí)保留較高的信息密度。且 36 進(jìn)制在客戶輸入時(shí),不需要考慮大小寫問(wèn)題,用戶體驗(yàn)更好。

摘要算法選擇

MD5 算法已被證實(shí)存在碰撞漏洞,但在安全性要求相對(duì)不是很高的場(chǎng)景中,還是可以接受的。如果需要安全性更高的摘要算法,可以換成例如 SHA-256、國(guó)密 SM3 等更為安全算法,在得到簽名后截取 32 位 當(dāng)作 MD5 使用,實(shí)現(xiàn)安全性、用戶體驗(yàn)的兼顧。

36進(jìn)制字符集

因?yàn)?36 進(jìn)制是自行實(shí)現(xiàn)的,所以可以自定義字符集,大家可以在這一步對(duì)字符集排布順序進(jìn)行打亂,實(shí)現(xiàn)混淆效果。

非對(duì)稱方案

前面的授權(quán)碼方案可以提供一個(gè)方便輸入,長(zhǎng)度較短的授權(quán)碼字符串,但攜帶授權(quán)信息較少、密鑰(鹽值)需要內(nèi)置在客戶端中,遇到逆行破解場(chǎng)景,有鹽值泄露的可能性。

授權(quán)碼設(shè)計(jì)

非對(duì)稱加密我們可以使用 RSA 算法來(lái)實(shí)現(xiàn)。當(dāng)我們使用 RSA 算法時(shí),我們可以通過(guò)授權(quán)碼給客戶端攜帶更多信息,所以我們就以 JSON 為許可證內(nèi)容的載體。我們可以這樣設(shè)計(jì):

{
    "iss":"tpamis",
    "sub":"pord",
    "aud": "123456",
    "exp": "1861804800",
    "nbf": "1743436800",
    "iat":"1742728673",
    "rge":["功能a","功能b","功能b"]
}

接參考了 JWT 官方規(guī)定的 Payload 字段,設(shè)計(jì)的許可證 JSON 內(nèi)容,且這些字段可以根據(jù)需求隨意添加調(diào)整。

  • ? iss (issuer):授權(quán)項(xiàng)目
  • ? sub (subject):授權(quán)方式,prod 正式授權(quán)、test 測(cè)試授權(quán)
  • ? aud (audience):授權(quán)對(duì)象,客戶的機(jī)器碼
  • ? exp (expiration time):過(guò)期時(shí)間
  • ? nbf (Not Before):生效時(shí)間
  • ? iat (Issued At):簽發(fā)時(shí)間
  • ? rge:授權(quán)功能列表

生成授權(quán)碼

我們生成一對(duì) RSA 公私鑰,公鑰保存在客戶端,私鑰在我們手里,我們根據(jù)用戶的機(jī)器碼,生成一個(gè)授權(quán)碼,以上面為例,我額外擴(kuò)展了授權(quán)模塊功能,可以精確控制客戶允許使用的功能范圍。

  1. 1. 生成包含許可證信息的JSON 字符串
{"iss":"tpamis","sub":"pord","aud":"123456","exp":"1861804800","nbf":"1743436800","iat":"1742728673","rge":["功能a","功能b","功能b"]}
  1. 2. 然后我們使用 RSA 私鑰加密生成密文,這個(gè)密文就是我們需要提供給客戶的授權(quán)碼。
I0UQvjrw3achexYK/D2ciNbsN+d28meH56aQPvosR9ZAKX2xp+kFNMfOjgBH+ZCL5+ir0h+pibfyva5weFBEEy1WgPMSqSiFGL5jfNIpzRY+Ct8hqsrjZm20TONvEjE7gwhFHW0m0NvdpFmwvbOjQPLk5ipZkNWW2l/DvEkYyogVMxCAfcNmczv1x9c1MeyXp0ru7GQifF1q1wGn4SBljc61zfUbtsv5aHk7zibOrNu4DsXnGjnYmwRCqYogAhB7g4Wzxfx0chMED9ulakTC8G5rBwT2w+LNgxKP+Si/nsOL0PeBzwrLTYulJIQEoqNsjMkDJ4JbXa/uoWrRoIuMTg==

當(dāng)許可證內(nèi)容過(guò)多,導(dǎo)致密文過(guò)長(zhǎng)時(shí),可以考慮輸出一個(gè)密鑰文件給客戶,客戶在產(chǎn)品中上傳、選擇 密鑰文件,我們通過(guò)讀取密鑰文件來(lái)獲取授權(quán)碼。這樣體驗(yàn)更好。

授權(quán)碼驗(yàn)證

用戶將我們的授權(quán)碼輸入到軟件中,客戶端使用公鑰解密,解密成功則讀取進(jìn)入進(jìn)行進(jìn)一步的授權(quán)校驗(yàn),解密失敗直接提示授權(quán)碼錯(cuò)誤。

說(shuō)明:將公鑰內(nèi)置到客戶端,在極端情況下,存在反編譯的可能性。所以我們可以假設(shè)公鑰已經(jīng)泄露、不安全的狀態(tài)。不過(guò)只要私鑰不泄露,別人拿到公鑰也只能解密我們的許可證密文,而不能偽造一個(gè)許可證,相對(duì)來(lái)說(shuō)也是可以接受的。

代碼示例

以 Go 語(yǔ)言為例 加密解密過(guò)程如下

package main

import (
    "encoding/json"
    "fmt"
    "github.com/dromara/dongle"
)

func main() {
    // 聲明 map[string]any 許可證結(jié)構(gòu)
    licenseData := map[string]any{
        "iss""tpamis",
        "sub""pord",
        "aud""123456",
        "exp""1861804800",
        "nbf""1743436800",
        "iat""1742728673",
        "rge": []string{"功能a""功能b""功能b"},
    }

    // 將 map 轉(zhuǎn)換為 JSON 字符串
    jsonData, _ := json.Marshal(licenseData)
    // 使用RSA 私鑰 授權(quán)Json
    cipherText := dongle.Encrypt.FromBytes(jsonData).ByRsa(pkcs1PrivateKey).ToBase64String()
    fmt.Println("RSA密文", cipherText)
    
    // 客戶端 使用 公鑰進(jìn)行解密
    licenseJson := dongle.Decrypt.FromBase64String(cipherText).ByRsa(pkcs1PublicKey).ToString()
    fmt.Println("許可證Json", licenseJson)
}

var pkcs1PublicKey = []byte(`-----BEGIN RSA PUBLIC KEY-----
MIGJAoGBAK12MTd84qkCZzp4iLUj8YSUglaFMsFlv9KlIL4+Xts40PK3+wbsXPEw
cujGeUmdgMeZiK7SLLSz8QeE0v7Vs+cGK4Bs4qLtMGCiO6wEuyt10KsafTyBktFn
dk/+gBLr7B/b+9+HaMIIoJUdsFksdAg3cxTSpwVApe98loFNRfqDAgMBAAE=
-----END RSA PUBLIC KEY-----`
)

var pkcs1PrivateKey = []byte(`-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQCtdjE3fOKpAmc6eIi1I/GElIJWhTLBZb/SpSC+Pl7bONDyt/sG
7FzxMHLoxnlJnYDHmYiu0iy0s/EHhNL+1bPnBiuAbOKi7TBgojusBLsrddCrGn08
gZLRZ3ZP/oAS6+wf2/vfh2jCCKCVHbBZLHQIN3MU0qcFQKXvfJaBTUX6gwIDAQAB
AoGAFwAfEo56t5JcAcLNzccQVVYj2jkbO820G8hNiSxYA5WLD0QaAxcAU/Lqqbb3
ii1aUB0ppJS13NgnU6nnGGdZzUYBG1Hai6EkVyCGrI4amQ93AaVdKncL8gJ4RZAm
YzPPUwSMEESsu24pS1NF1G1Y8C+28b/Wr0oqOsCvL6PhsMECQQDwsPJJoWRx7ZJw
E1K5KLT0cXKyrIpyXY3I6tyA5imCzOzccf3d1vDgB0L9sdSO7bG3ceSwpAeiWEbg
5jGZemPzAkEAuH6U4pEI4AMbWnatpK55Rc235NDgmT3VyIuRaKC02YXAZ+jznFep
XMd4DTli4R9r3j2YVhUpyDVbdQpFH98DMQJAQpOvcU6DSkA80WOG7lCkPTlkUKgJ
Y7kdDwZoF/+SW+vzWMbvQf3CgzV/Ak2+TgrRrbyDVZkJw45HjM4fyiRgoQJBALH/
/qlxgPyQQs3O/s2KQBsm1auAE5IF5MLuVUZ69sF/mBko2hEXSqHnGV645TuKU0pC
Zz12ga9WO3z6gaK0SaECQQDah1pKt9ViBBy4USXK3OWXEloHuTwmyr9AbLqqI5tQ
2eNuH0NkuJYQmnXmHLbKOELoYocldEBXmkzPXSN+X9kV
-----END RSA PRIVATE KEY-----`
)

JWT 方案

JWT 方案則是直接使用標(biāo)準(zhǔn)的 JWT 庫(kù)來(lái)實(shí)現(xiàn)授權(quán)碼的簽發(fā)功能,客戶端和服務(wù)端共享 JWT 的密鑰來(lái)驗(yàn)證授權(quán)簽名的有效性。

本方案的優(yōu)點(diǎn)是可以充分利用現(xiàn)有的標(biāo)準(zhǔn)化 JWT 庫(kù),只需定義一個(gè)密鑰,而無(wú)需進(jìn)行過(guò)多的開發(fā),但許可證內(nèi)容會(huì)直接暴露給客戶,也可以考慮 JWE,需自行抉擇。

JWT Header
{
  "alg": "HS256",
  "typ": "JWT"
}

JWT Payload
{
  "iss": "tpamis",
  "sub": "pord",
  "aud": "123456",
  "exp": "1861804800",
  "nbf": "1743436800",
  "iat": "1742728673",
  "rge": [
    "功能a",
    "功能b",
    "功能b"
  ]
}

密鑰
dbkuaizi.com

JWT Token
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJ0cGFtaXMiLCJzdWIiOiJwb3JkIiwiYXVkIjoiMTIzNDU2IiwiZXhwIjoiMTg2MTgwNDgwMCIsIm5iZiI6IjE3NDM0MzY4MDAiLCJpYXQiOiIxNzQyNzI4NjczIiwicmdlIjpbIuWKn-iDvWEiLCLlip_og71iIiwi5Yqf6IO9YiJdfQ.izIAwMyiLxPiHrWf-FDGu3fHMvfaC7bqEh40ha8YYAA

結(jié)尾

沒(méi)有絕對(duì)的安全

任何安全領(lǐng)域的手段都是相對(duì)安全,沒(méi)有絕對(duì)的安全。再?gòu)?fù)雜的授權(quán)碼的本質(zhì)只能是 防君子不防小人,例如用戶可以通過(guò)逆向 得到你的鹽值、甚至直接修改你的程序邏輯跳過(guò)驗(yàn)證的邏輯,更何況我們的場(chǎng)景中只有離線校驗(yàn)的邏輯。

防止時(shí)鐘回?fù)?/span>

時(shí)鐘回?fù)苁侵福褪怯脩糁苯油ㄟ^(guò)修改系統(tǒng)時(shí)間到軟件授權(quán)到期之前,從而繼續(xù)使用軟件的目的。那么我們?cè)陔x線場(chǎng)景中如何去避免這樣的情況發(fā)生呢?
首先我需要聲明的是,離線授權(quán)場(chǎng)景中,不能徹底避免這種情況(除了獨(dú)立時(shí)鐘的加密狗),我們能做的就是通過(guò)代碼邏輯盡可能規(guī)避這種情況的發(fā)生,一般有這幾種手段:

記錄上一次運(yùn)行時(shí)間

眾所周知,時(shí)間是不會(huì)倒流的,也就是說(shuō)軟件的第二次運(yùn)行時(shí)間,不可能小于上一次運(yùn)行時(shí)的系統(tǒng)時(shí)間。
所以,在軟件每次運(yùn)行時(shí)我們可以先記錄當(dāng)前時(shí)間,并與上一次系統(tǒng)時(shí)間做對(duì)比,若第二次運(yùn)行時(shí)的系統(tǒng)時(shí)間小于之前記錄的時(shí)間,則認(rèn)為出現(xiàn)了系統(tǒng)時(shí)鐘回?fù)艿膯?wèn)題,直接提示用戶并終止軟件運(yùn)行。

安全的存儲(chǔ)時(shí)間標(biāo)記
那么如何保證我們存儲(chǔ)的時(shí)間沒(méi)有被篡改呢?我們可以通過(guò) (時(shí)間戳.鹽)+md5 的方式實(shí)現(xiàn):
例如:時(shí)間戳為 1717487962 鹽 是 abcdefg,
通過(guò): md5('1717487962.abcdefg') 摘要算法,獲得時(shí)間戳簽名:a06de98fc28e45bf38a9a5f27630cd03。
然后將這樣的字符串進(jìn)行存儲(chǔ):1717487962.a06de98fc28e45bf38a9a5f27630cd03,啟動(dòng)時(shí)再通過(guò)上面的邏輯進(jìn)行校驗(yàn),即可保證 記錄的時(shí)間不被修改。

如何防止用戶刪除時(shí)間標(biāo)記
可以在打包的時(shí)候,就記錄一個(gè)打包時(shí)間作為初始化時(shí)間戳,這樣即使用戶第一次運(yùn)行也必須有時(shí)間戳。
若沒(méi)讀取不到時(shí)間戳標(biāo)記,則說(shuō)明用戶人為清理了時(shí)間標(biāo)記,結(jié)束運(yùn)行。

與業(yè)務(wù)數(shù)據(jù)強(qiáng)關(guān)聯(lián)

如果你產(chǎn)品運(yùn)行過(guò)程中產(chǎn)生的業(yè)務(wù)數(shù)據(jù)很重要,也可以使用業(yè)務(wù)中的時(shí)間戳來(lái)做時(shí)鐘回?fù)苄r?yàn),例如使用最后一條訂單的創(chuàng)建時(shí)間。
若業(yè)務(wù)數(shù)據(jù)很重要,用戶總不可能為了繼續(xù)使用軟件而刪掉業(yè)務(wù)數(shù)據(jù)吧。

拋磚引玉

授權(quán)碼的設(shè)計(jì)方案有很多,這里只是整理了我用過(guò)的幾種方案,大家可以根據(jù)自己的需要對(duì)邏輯進(jìn)行調(diào)整,如果你有更好的方案,歡迎留言交流。


閱讀原文:原文鏈接


該文章在 2025/3/25 10:29:44 編輯過(guò)
關(guān)鍵字查詢
相關(guān)文章
正在查詢...
點(diǎn)晴ERP是一款針對(duì)中小制造業(yè)的專業(yè)生產(chǎn)管理軟件系統(tǒng),系統(tǒng)成熟度和易用性得到了國(guó)內(nèi)大量中小企業(yè)的青睞。
點(diǎn)晴PMS碼頭管理系統(tǒng)主要針對(duì)港口碼頭集裝箱與散貨日常運(yùn)作、調(diào)度、堆場(chǎng)、車隊(duì)、財(cái)務(wù)費(fèi)用、相關(guān)報(bào)表等業(yè)務(wù)管理,結(jié)合碼頭的業(yè)務(wù)特點(diǎn),圍繞調(diào)度、堆場(chǎng)作業(yè)而開發(fā)的。集技術(shù)的先進(jìn)性、管理的有效性于一體,是物流碼頭及其他港口類企業(yè)的高效ERP管理信息系統(tǒng)。
點(diǎn)晴WMS倉(cāng)儲(chǔ)管理系統(tǒng)提供了貨物產(chǎn)品管理,銷售管理,采購(gòu)管理,倉(cāng)儲(chǔ)管理,倉(cāng)庫(kù)管理,保質(zhì)期管理,貨位管理,庫(kù)位管理,生產(chǎn)管理,WMS管理系統(tǒng),標(biāo)簽打印,條形碼,二維碼管理,批號(hào)管理軟件。
點(diǎn)晴免費(fèi)OA是一款軟件和通用服務(wù)都免費(fèi),不限功能、不限時(shí)間、不限用戶的免費(fèi)OA協(xié)同辦公管理系統(tǒng)。
Copyright 2010-2025 ClickSun All Rights Reserved

主站蜘蛛池模板: 国内精品视频成人一区二区 | 国产男生夜间福利免费网站 | 91精品免费久久久久久久久 | 99福利视频 | 中文字幕有码在线观看 | 日韩高清在线观看不卡一区二区 | 国产精品臀控福利在线观看 | 国产jk制服白 | 国产成人无码无卡在线观看 | 国产v片在线播放免费无遮挡 | 欧美性做爰大片免费看软件男组长 | 亚洲综合无码久久精品综合 | 果冻破解版无限app旧版下载 | 二区啪视频 | 国产aⅴ无码专区亚洲av麻豆 | 亚洲性日韩精品一区二区 | 亚洲免费成人网 | 91香蕉视频在线 | 一级片中| 国产激情精品一区二区三区 | 国产精品一区二区三区在线观看 | 国产高清不卡一区二区在线视频 | 91嫩草国产在线观看免费 | 国产精品扒开腿做爽爽爽视频 | 一区二区三区精密机械 | av大全一区二区三区 | 韩国精品视频一区二区在线播放 | 欧美成人免费大片 | 日本高清中文字幕在线 | 国产精品一区在线观看播放 | 成年女人免 | 成人自拍午夜在线观看 | 97超碰人人澡人人爱 | 无码精品国产一区二区 | 麻豆亚洲无矿砖码区 | 丰满少妇熟女高潮流白浆 | 欧美日韩精品一区二区三区视频在线 | 熟女精品视频一区二区三区 | 亚洲福利网站 | 91传媒制片厂制作网 | 亚洲mv大片免费网站 |