Sự khác biệt của hai kết quả là do việc sử dụng mã hóa Base64URL trong mã C # so với mã hóa Base64 trong node.js.
Base64URLvà Base64gần như giống hệt nhau, nhưng Base64mã hóa dùng ký tự +, /và =, trong đó có một ý nghĩa đặc biệt trong URL và do đó có thể tránh được. Trong Base64URLbảng mã +được thay thế bằng -, /với _và =(ký tự đệm ở cuối) được thay thế bằng %20hoặc đơn giản là bỏ qua.
Trong mã của bạn, bạn đang tính toán băm HMAC-SHA256, vì vậy bạn nhận được kết quả 256 bit, có thể được mã hóa thành 32 byte. Trong Base64/ Base64URLmọi ký tự đại diện cho 6 bit, do đó bạn sẽ cần 256/6 = 42,66 => 43 ký tự Base64. Với 43 ký tự, bạn sẽ có 2 bit 'đơn độc' ở cuối, do đó một dấu đệm char ( =) được thêm vào. Câu hỏi bây giờ là tại sao lại HttpServerUtility.UrlTokenEncodethêm 1một ký tự thay thế cho ký tự đệm ở cuối. Tôi không tìm thấy gì trong tài liệu . Nhưng bạn nên nhớ rằng dù sao thì nó cũng không đáng kể.
Để có được điều tương tự trong node.js, bạn có thể sử dụng gói base64url hoặc chỉ sử dụng các replacecâu lệnh đơn giản trên băm mã hóa base64.
Với gói base64url:
const base64url = require('base64url');
var hmacB64 = "Pn55YBwEH2S2BEM5qlNrq+LMNE8BDdHYwbWKFEHiPZo="
var hmacB64url = base64url.fromBase64(hmacb64)
console.log(hmacB64url)
Kết quả là:
Pn55YBwEH2S2BEM5qlNrq-LMNE8BDdHYwbWKFEHiPZo
như bạn có thể thấy, thư viện này chỉ bỏ qua ký tự đệm.
Với replace, cũng thay thế phần đệm =bằng 1:
var hmacB64 = "Pn55YBwEH2S2BEM5qlNrq+LMNE8BDdHYwbWKFEHiPZo="
console.log(hmacb64.replace(/\//g,'_').replace(/\+/g,'-').replace(/\=+$/m,'1'))
Kết quả là:
Pn55YBwEH2S2BEM5qlNrq-LMNE8BDdHYwbWKFEHiPZo1
Tôi đã thử mã C # với dữ liệu khác nhau và luôn nhận được '1' ở cuối, vì vậy việc thay thế =bằng 1có vẻ ổn, mặc dù nó có vẻ không phù hợp với RFC.
Cách thay thế khác, nếu đây là một lựa chọn cho bạn, là thay đổi mã C #. Sử dụng base64mã hóa thông thường cộng với thay thế chuỗi để nhận base64urlđầu ra thay vì sử dụngHttpServerUtility.UrlTokenEncode
Một giải pháp khả thi cho điều đó được mô tả ở đây