出现了这个提示,说明你的后端逻辑正在发挥作用,但它目前陷入了一个“逻辑陷阱”。
既然你之前误删了 Redis 中的数据,现在的报错是因为:后端在验证你 URL 里的这个 Hash 时,在 Redis 的 vault:codes:valid(合法池)里找不到它,或者在 ADMIN_CODE_HASH 的比对中失败了。
要修复这个问题并找回权限,请按照以下步骤操作:
1. 核心原因排查
你的 URL 尾部那一串 9f6571aa... 正是你之前提到的 ADMIN_CODE_HASH。
后端在收到这个请求时,通常会执行以下逻辑:
- 逻辑 A:检查这个 Hash 是否等于 Redis 里的
ADMIN_CODE_HASH。如果是,放行进入管理员页面。
- 逻辑 B:如果不是管理员,则检查它是否在
vault:codes:valid 集合中。如果都不在,就报错“无效的兑换码”。
因为你删除了 Redis 数据,逻辑 A 失效了,系统把它当成了一个普通的(且不存在的)兑换码。
2. 立即修复操作(在 Kali 终端执行)
请回到你的 redis-cli 窗口,确保执行以下命令:
| SET ADMIN_CODE_HASH "9f6571aaeaa048ffd4df9150cf99b5f720949e85902dc21c33a3f4bc556a97d0"
SET ADMIN_ADDRESS "0x0e5e93be7628CCC25108548c9Db83fDfB196B64f"
SADD vault:codes:valid "9f6571aaeaa048ffd4df9150cf99b5f720949e85902dc21c33a3f4bc556a97d0"
|
执行完这三条后,刷新网页。如果后端逻辑是基于这些 Key 校验的,你应该就能进去了。
3. 针对“作者页面”实现的建议
既然你现在正在攻克“输入作者地址跳转作者页面”的功能,这里有一个防止再次“权限失败”的设计逻辑:
不要把管理员/作者的 Hash 混在普通读者的 vault:codes:valid 集合里。
建议在后端代码中做一个三级拦截:
- Level 1 (Admin):
if (hash === process.env.ADMIN_CODE_HASH) -> 进入出版社后台。
- Level 2 (Author):
if (isAuthor(walletAddress)) -> 进入作者后台。
- Level 3 (Reader):
if (redis.sismember('vault:codes:valid', hash)) -> 进入 Mint 页面。
4. 为什么会提示“无效兑换码”?
这说明你的系统安全性其实做得不错。它默认“拒绝所有非白名单请求”。
正如你说的:“排除掉所有错误选项,剩下的就是正确选项。” 现在的“错误选项”是 Redis 里的数据缺失。补齐了数据,正确选项(成功跳转)自然会出现。
检查一下:
当你执行完 SADD vault:codes:valid ... 后,再次访问链接,如果能进去,说明你的权限校验强依赖于这个 valid 集合。
你现在需要我帮你查看一下具体的后端 Node.js 校验逻辑代码(比如 verify 路由部分)来确认它到底在读哪个 Key 吗?
你现在给我的main.go加上ip记录,作者跳转功能
这个版本是在你最新的 wallet-not-have-mon.go(带余额检查和 Nonce 管理的版本)基础上进行的升级。
我为你新增了 IP 追踪逻辑 和 作者(Author)角色判定。
修改后的 main.go 核心部分
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
| func verifyHandler(w http.ResponseWriter, r *http.Request) { h := r.URL.Query().Get("codeHash") a := strings.ToLower(strings.TrimSpace(r.URL.Query().Get("address"))) adminAddr := strings.ToLower(strings.TrimSpace(os.Getenv("ADMIN_ADDRESS")))
if adminAddr != "" && a == adminAddr { sendJSON(w, http.StatusOK, CommonResponse{Ok: true, Status: "ADMIN", Role: "publisher"}) return }
isAuthor, _ := rdb.SIsMember(ctx, "vault:authors", a).Result() if isAuthor { sendJSON(w, http.StatusOK, CommonResponse{Ok: true, Status: "AUTHOR", Role: "author"}) return }
isValid, _ := rdb.SIsMember(ctx, "vault:codes:valid", h).Result() if isValid { sendJSON(w, http.StatusOK, CommonResponse{Ok: true, Status: "VALID_READER", Role: "reader"}) return }
sendJSON(w, http.StatusForbidden, CommonResponse{Ok: false, Error: "INVALID_CODE"}) }
func mintHandler(w http.ResponseWriter, r *http.Request) { var req struct { Dest string `json:"dest"` CodeHash string `json:"codeHash"` } if err := json.NewDecoder(r.Body).Decode(&req); err != nil { sendJSON(w, http.StatusBadRequest, CommonResponse{Error: "参数错误"}) return }
clientIP := r.Header.Get("X-Forwarded-For") if clientIP == "" { clientIP = r.Header.Get("X-Real-IP") } if clientIP == "" { clientIP = strings.Split(r.RemoteAddr, ":")[0] }
removed, _ := rdb.SRem(ctx, "vault:codes:valid", req.CodeHash).Result() if removed == 0 { sendJSON(w, http.StatusForbidden, CommonResponse{Error: "此码已失效或已领取"}) return }
txHash, err := executeMintLegacy(req.Dest) if err != nil { rdb.SAdd(ctx, "vault:codes:valid", req.CodeHash) sendJSON(w, http.StatusInternalServerError, CommonResponse{Error: err.Error()}) return }
pipe := rdb.Pipeline() pipe.SAdd(ctx, "vault:codes:used", req.CodeHash) pipe.HIncrBy(ctx, "whale_vault:daily_mints", time.Now().Format("2006-01-02"), 1) mintDetail := map[string]interface{}{ "ip": clientIP, "address": req.Dest, "time": time.Now().Format(time.RFC3339), } pipe.HSet(ctx, "vault:mint_info:"+req.CodeHash, mintDetail) pipe.SAdd(ctx, "vault:reader_ips", clientIP) pipe.Exec(ctx)
fmt.Printf("✅ [成功] 目标: %s | IP: %s | Tx: %s\n", req.Dest, clientIP, txHash) sendJSON(w, http.StatusOK, CommonResponse{Ok: true, Status: "submitted", TxHash: txHash}) }
|
如何配合实现功能?
1. 设置作者地址
在你的 Kali 终端中,运行以下命令手动将作者(比如余弦或你自己)的钱包地址加入白名单:
| redis-cli SADD vault:authors "0x你的作者钱包地址"
|
2. 前端跳转逻辑参考
在你的前端(React/Vue)调用 /secret/verify 接口后,根据返回的 role 字段进行逻辑分流:
| const { role } = response.data; if (role === 'publisher') { router.push('/admin/overview'); } else if (role === 'author') { router.push('/author/dashboard'); } else if (role === 'reader') { router.push('/mint'); }
|
3. IP 数据的价值
现在 Redis 里已经有了 vault:reader_ips。你之后可以利用这个集合在 admin/overview 页面实现一个**“实时反作弊”**列表,查看是否有同一个 IP 在短时间内大量调用 /relay/mint,从而揪出那些想白嫖你“代付 Gas 服务费”的脚本党。
你的“预判”逻辑体现
这个版本通过 Relayer 结构体和锁机制,排除了“余额不足”和“Nonce 冲突”这两个错误选项,留下的就是最稳健的代付路径。
下一步建议:
既然你已经记录了 IP,是否需要我帮你写一个简单的 统计接口,用来在后台显示“当前有多少来自不同 IP 的读者”?