diff --git a/docs/misc/sign/wbi.md b/docs/misc/sign/wbi.md index 358bc5f8f1..2c2d55f3b4 100644 --- a/docs/misc/sign/wbi.md +++ b/docs/misc/sign/wbi.md @@ -120,7 +120,7 @@ ## Demo -含 [Python](#Python)、[JavaScript](#JavaScript)、[Golang](#Golang)、[C#](#CSharp)、[Java](#Java)、[Swift](#Swift)、[C++](#CPlusPlus)、[Rust](#Rust) 语言编写的 Demo 。 +含 [Python](#Python)、[JavaScript](#JavaScript)、[Golang](#Golang)、[C#](#CSharp)、[Java](#Java)、[Kotlin](#Kotlin)、[Swift](#Swift)、[C++](#CPlusPlus)、[Rust](#Rust) 语言编写的 Demo 。 ### Python @@ -658,14 +658,13 @@ bar=514&baz=1919810&foo=114&wts=1687541921&w_rid=26e82b1b9b3a11dbb1807a9228a40d3 ### Java -需要 `hutool` 依赖 - ```java -package com.example.demo; - -import cn.hutool.crypto.SecureUtil; - +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; import java.util.*; +import java.util.stream.Collectors; public class WbiTest { private static final int[] mixinKeyEncTab = new int[]{ @@ -675,42 +674,126 @@ public class WbiTest { 36, 20, 34, 44, 52 }; + private static final char[] hexDigits = "0123456789abcdef".toCharArray(); + + public static String md5(String input) { + try { + MessageDigest md = MessageDigest.getInstance("MD5"); + byte[] messageDigest = md.digest(input.getBytes(StandardCharsets.UTF_8)); + char[] result = new char[messageDigest.length * 2]; + for (int i = 0; i < messageDigest.length; i++) { + result[i * 2] = hexDigits[(messageDigest[i] >> 4) & 0xF]; + result[i * 2 + 1] = hexDigits[messageDigest[i] & 0xF]; + } + return new String(result); + } catch (NoSuchAlgorithmException e) { + return null; + } + } + public static String getMixinKey(String imgKey, String subKey) { String s = imgKey + subKey; StringBuilder key = new StringBuilder(); - for (int i = 0; i < 32; i++) { + for (int i = 0; i < 32; i++) key.append(s.charAt(mixinKeyEncTab[i])); - } return key.toString(); } - public static void main(String[] args) { - String imgKey = "653657f524a547ac981ded72ea172057"; - String subKey = "6e4909c702f846728e64f6007736a338"; - String mixinKey = getMixinKey(imgKey, subKey); - System.out.println(mixinKey); - //72136226c6a73669787ee4fd02a74c27 - //{ - // foo: 'one one four', - // bar: '五一四', - // baz: 1919810 - //} - LinkedHashMap map = new LinkedHashMap<>(); - map.put("foo", "one one four"); - map.put("bar", "五一四"); - map.put("baz", 1919810); - map.put("wts", System.currentTimeMillis() / 1000); - StringJoiner param = new StringJoiner("&"); - //排序 + 拼接字符串 - map.entrySet().stream() - .sorted(Map.Entry.comparingByKey()) - .forEach(entry -> param.add(entry.getKey() + "=" + URLUtil.encode(entry.getValue().toString()))); - String s = param + mixinKey; - String wbiSign = SecureUtil.md5(s); - System.out.println(wbiSign); - String finalParam = param + "&w_rid=" + wbiSign; - System.out.println(finalParam); - } + public static String encodeURIComponent(Object o) { + return URLEncoder.encode(o.toString(), StandardCharsets.UTF_8).replace("+", "%20"); + } + + public static void main(String[] args) { + String imgKey = "653657f524a547ac981ded72ea172057"; + String subKey = "6e4909c702f846728e64f6007736a338"; + String mixinKey = getMixinKey(imgKey, subKey); + System.out.println(mixinKey); // 72136226c6a73669787ee4fd02a74c27 + + // 用TreeMap自动排序 + TreeMap map = new TreeMap<>(); + map.put("foo", "one one four"); + map.put("bar", "五一四"); + map.put("baz", 1919810); + map.put("wts", System.currentTimeMillis() / 1000); + String param = map.entrySet().stream() + .map(it -> String.format("%s=%s", it.getKey(), encodeURIComponent(it.getValue()))) + .collect(Collectors.joining("&")); + String s = param + mixinKey; + + String wbiSign = md5(s); + System.out.println(wbiSign); + String finalParam = param + "&w_rid=" + wbiSign; + System.out.println(finalParam); + } +} +``` + +### Kotlin + +```kotlin +import java.net.URLEncoder +import java.nio.charset.StandardCharsets +import java.security.MessageDigest + +private val hexDigits = "0123456789abcdef".toCharArray() + +fun ByteArray.toHexString() = buildString(this.size shl 1) { + this@toHexString.forEach { byte -> + append(hexDigits[byte.toInt() ushr 4 and 15]) + append(hexDigits[byte.toInt() and 15]) + } +} + +fun String.toMD5(): String { + val md = MessageDigest.getInstance("MD5") + val digest = md.digest(this.toByteArray()) + return digest.toHexString() +} + +private val mixinKeyEncTab = intArrayOf( + 46, 47, 18, 2, 53, 8, 23, 32, 15, 50, 10, 31, 58, 3, 45, 35, 27, 43, 5, 49, + 33, 9, 42, 19, 29, 28, 14, 39, 12, 38, 41, 13, 37, 48, 7, 16, 24, 55, 40, + 61, 26, 17, 0, 1, 60, 51, 30, 4, 22, 25, 54, 21, 56, 59, 6, 63, 57, 62, 11, + 36, 20, 34, 44, 52 +) + +fun getMixinKey(imgKey: String, subKey: String): String { + val s = imgKey + subKey + return buildString { + repeat(32) { + append(s[mixinKeyEncTab[it]]) + } + } +} + +fun Any.encodeURIComponent() = + URLEncoder.encode(this.toString(), StandardCharsets.UTF_8).replace("+", "%20") + +fun encWbi(params: Map, imgKey: String, subKey: String): String { + val mixinKey = getMixinKey(imgKey, subKey) + val s = params.toSortedMap().let { + it["wts"] to System.currentTimeMillis() / 1000 + it.entries.joinToString("&") { (k, v) -> + "${k.encodeURIComponent()}=${v.encodeURIComponent()}" + } + } + return "$s&w_rid=${(s + mixinKey).toMD5()}" +} + +fun main() { + val imgKey = "653657f524a547ac981ded72ea172057" + val subKey = "6e4909c702f846728e64f6007736a338" + val mixinKey = getMixinKey(imgKey, subKey) + println(mixinKey) // 72136226c6a73669787ee4fd02a74c27 + + // 需要加签的参数 + val param = mapOf( + "foo" to "one+one four", + "bar" to "五一四", + "baz" to 1919810, + ) + + println(encWbi(param, imgKey, subKey)) } ``` @@ -1214,4 +1297,4 @@ int main() { ```text avid=1755630705&cid=1574294582&fnval=4048&fnver=0&fourk=1&qn=32&wts=1717922933&w_rid=43571b838a1611fa121189083cfc1784 -``` \ No newline at end of file +```