Telegram WebApp initDataUnsafe哈希验证Java实现结果不匹配问题求助
Telegram WebApp initDataUnsafe哈希验证Java实现结果不匹配问题求助
我刚接触Telegram开发,现在想用Java验证Telegram WebApp(不是登录组件)提供的initData哈希值,已经严格按照官方文档和Spring Boot相关的Telegram认证指南来操作了,但计算出来的哈希值始终和Telegram返回的对不上,实在卡壳了,来求助各位大佬!
根据Telegram官方要求,验证用的data-check字符串需要把除了hash之外的所有字段按字母顺序排序,每个字段以key=value的形式用换行符\n拼接——这一步我确认已经照做了。
我的场景和数据
我通过Telegram Mini App的window.Telegram.WebApp.initDataUnsafe拿到的原始数据结构大概是这样的:
{ "id": 785xxxxxx, "first_name": "xxxxxxx", "last_name": "xxxxxx", "language_code": "en", "allows_write_to_pm": true, "photo_url": "https://t.me/i/userpic/320/abc123.svg", "auth_date": "1750072455", "hash": "a55cdfdexxxxxx" }
我的Java验证代码
import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import java.nio.charset.StandardCharsets; import java.util.Map; import java.util.TreeMap; import java.util.stream.Collectors; public class TelegramAuthValidator { public static boolean isValid(Map<String, String> authData, String botToken) { String receivedHash = authData.get("hash"); authData.remove("hash"); // Step 1: 构建data_check_string Map<String, String> sorted = new TreeMap<>(authData); String dataCheckString = sorted.entrySet().stream() .map(e -> e.getKey() + "=" + e.getValue()) .collect(Collectors.joining("\n")); try { // Step 2: 生成密钥(用"WebAppData"作为密钥,对botToken做HMAC_SHA256) Mac mac1 = Mac.getInstance("HmacSHA256"); mac1.init(new SecretKeySpec("WebAppData".getBytes(StandardCharsets.UTF_8), "HmacSHA256")); byte[] secretKey = mac1.doFinal(botToken.getBytes(StandardCharsets.UTF_8)); // Step 3: 用生成的密钥对dataCheckString做HMAC_SHA256 Mac mac2 = Mac.getInstance("HmacSHA256"); mac2.init(new SecretKeySpec(secretKey, "HmacSHA256")); byte[] hmac = mac2.doFinal(dataCheckString.getBytes(StandardCharsets.UTF_8)); String calculatedHash = bytesToHex(hmac); System.out.println("DataCheckString: " + dataCheckString); System.out.println("预期Hash: " + receivedHash); System.out.println("计算Hash: " + calculatedHash); return calculatedHash.equalsIgnoreCase(receivedHash); } catch (Exception e) { e.printStackTrace(); return false; } } // 补充我用的bytes转hex方法(避免是这里出问题) private static String bytesToHex(byte[] bytes) { StringBuilder sb = new StringBuilder(); for (byte b : bytes) { sb.append(String.format("%02x", b)); } return sb.toString(); } }
我已经尝试过的排查步骤
- 反复检查
dataCheckString,确保没有多余的换行、空格或特殊字符 - 对比过能正常工作的PHP实现逻辑,步骤完全对齐
- 试过两种密钥生成方式:直接对botToken做SHA256,以及官方要求的HMAC_SHA256(botToken, "WebAppData")
- 确认字段排序是严格按字母顺序,值的格式(比如布尔值
true的大小写、日期字符串)和Telegram返回的完全一致
但不管怎么调,计算出来的哈希值和Telegram返回的就是对不上,实在找不到问题出在哪了。有没有大佬能帮我分析下,到底哪里错了?怎么才能在Java里成功验证Telegram WebApp的initDataUnsafe哈希值?
内容来源于stack exchange




