将C#安全令牌生成功能迁移至Java(适配Android应用)
实现与C#一致的Java令牌生成方法
我仔细拆解了你提供的C# GenToken 方法的执行流程,然后对应实现了完全匹配的Java代码,这样生成的令牌就能和C#版本完全一致,解决认证失败的问题。
先明确C#代码的核心步骤
要保证结果一致,必须严格复刻每一步的行为:
- 将输入字符串
str转换为UTF-8字节数组(C#里通过MemoryStream传递,本质还是用这些字节计算哈希) - 使用
secret的UTF-8字节初始化HMAC-SHA256哈希器 - 计算哈希值,将哈希字节数组转换为大写十六进制字符串(C#的
BitConverter.ToString会用-分隔每个字节,之后移除所有-) - 拼接成
哈希字符串.str的格式 - 将拼接后的字符串转为UTF-8字节,再做标准Base64编码返回
对应Java实现代码
import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import java.nio.charset.StandardCharsets; import java.util.Base64; public class TokenGenerator { public static String genToken(String secret, String str) throws Exception { // 初始化HMAC-SHA256哈希器,对应C#的HMACSHA256 Mac hmacSha256 = Mac.getInstance("HmacSHA256"); SecretKeySpec secretKey = new SecretKeySpec( secret.getBytes(StandardCharsets.UTF_8), "HmacSHA256" ); hmacSha256.init(secretKey); // 计算哈希:C#里的MemoryStream只是传递str的UTF-8字节,直接用doFinal更高效且结果一致 byte[] hashBytes = hmacSha256.doFinal(str.getBytes(StandardCharsets.UTF_8)); // 转换为大写十六进制字符串(复刻BitConverter.ToString + Replace("-", "")的行为) StringBuilder hashStrBuilder = new StringBuilder(); for (byte b : hashBytes) { // %02X保证每个字节转成两位大写十六进制,不足补0 hashStrBuilder.append(String.format("%02X", b)); } String hashStr = hashStrBuilder.toString(); // 拼接哈希字符串与原str String tokenRaw = hashStr + "." + str; // 转UTF-8字节后做标准Base64编码,对应C#的Convert.ToBase64String return Base64.getEncoder().encodeToString(tokenRaw.getBytes(StandardCharsets.UTF_8)); } // 测试你的给定参数 public static void main(String[] args) throws Exception { String secret = "7353388933d07b2a1ef462c9d3f4e8ca"; String str = "{\"userId\":\"bcf4fc83-291a-11e7-9def-06948e004f29\",\"expires\":1516015203090}"; String result = genToken(secret, str); System.out.println(result); // 输出会和你提供的C#结果完全一致: // OTQyMDk1NTI2Mzc3NDYyRjk1RTYzQzUzNUVCNzg3MDQ1NjlBNDQ5OEM1MTM1N0I2QTQ3REY1OTA5M0Q3MjMzQS57InVzZXJJZCI6ImJjZjRmYzgzLTI5MWEtMTFlNy05ZGVmLTA2OTQ4ZTAwNGYyOSIsImV4cGlyZXMiOjE1MTYwMTUyMDMwOTB9 } }
关键细节说明
- 哈希算法一致性:Java的
HmacSHA256和C#的HMACSHA256是完全相同的算法,只要密钥和输入字节一致,哈希结果就一致。 - 十六进制转换:C#的
BitConverter.ToString生成的是大写、带-分隔的十六进制字符串,我们通过%02X格式化每个字节,直接生成无分隔符的大写十六进制字符串,和Replace("-", "")的结果完全匹配。 - Base64编码:Java的
Base64.getEncoder()和C#的Convert.ToBase64String都是采用标准Base64编码规则,没有额外的URL安全转换,保证结果一致。
运行测试用例后,你会得到和C#代码完全相同的输出,这样就能通过服务器的认证了。
内容的提问来源于stack exchange,提问作者DaChMo
相关产品推荐
相关产品推荐

