所以我很困惑。我知道有很多用于 JS 的 Base64 编码器/解码器,但没有用于修改后的(以及 Facebook 喜欢的)Base64URL 变体。到目前为止,在 stackoverflow 上的搜索已经一无所获。
是的,我可以使用 PHP 或其他服务器端库来解码它,但我试图保持它的通用性,无论我使用什么平台......例如,如果我要托管一个仅 HTML 的 Facebook Amazon S3/CloudFront 上的应用程序,仅使用其 JS SDK 和 jQuery 来处理表单和获取数据。
也就是说,有人知道 JavaScript 的 Base64URL 特定解码器吗?
提前致谢!
在解码之前使用它:
var decode = function(input) {
// Replace non-url compatible chars with base64 standard chars
input = input
.replace(/-/g, '+')
.replace(/_/g, '/');
// Pad out with standard base64 required padding characters
var pad = input.length % 4;
if(pad) {
if(pad === 1) {
throw new Error('InvalidLengthError: Input base64url string is the wrong length to determine padding');
}
input += new Array(5-pad).join('=');
}
return input;
}
使用此功能后您可以使用任何base64解码器
解决方案:
var b64str = base64.encode('foo bar');
// fix padding according to the new format
b64str = b64str.padRight(b64str.length + (4 - b64str.length % 4) % 4, '=');
使用这个很棒的base64编码/解码:http://code.google.com/p/stringencoders/source/browse/trunk/javascript/base64.js
还取决于padRight方法:
String.prototype.padRight = function(n, pad){
t = this;
if(n > this.length)
for(i = 0; i < n-this.length; i++)
t += pad;
return t;
}
mohamed 的回答非常有帮助,谢谢!
如果您遇到这种情况:
throw new Error("InvalidLengthError: Input base64url string is the wrong length to determine padding");
...您可能正在使用它来解码 JSON Web 令牌 (JWT)。
但是为此,您需要(在替换需要替换的字符之后)正确拆分 JWT 的 3 个部分(“.”字符),然后在尝试使用该答案中的代码进行解码之前填充每个部分(https ://stackoverflow.com/a/51838635/1143126)。
要快速查看 JWT 内部,如果对安全性并不重要(例如,如果仅用于本地测试),则可以使用 https://jwt.io/。
使用
TextEncoder
界面和 btoa()
功能,将 +
替换为 -
,并将 /
替换为 _
。最后,删除在 Base64 填充期间添加的尾随 =
字符。对于解码,过程相反。
function base64URLencode(str) {
const utf8Arr = new TextEncoder().encode(str);
const base64Encoded = btoa(utf8Arr);
return base64Encoded.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
}
function base64URLdecode(str) {
const base64Encoded = str.replace(/-/g, '+').replace(/_/g, '/');
const padding = str.length % 4 === 0 ? '' : '='.repeat(4 - (str.length % 4));
const base64WithPadding = base64Encoded + padding;
return atob(base64WithPadding)
.split('')
.map(char => String.fromCharCode(char.charCodeAt(0)));
}
我认为进行Base64/Base64URL解码最有效的方法是直接在函数中解码,而不是把Base64URL改为Base64然后解码。我编写了一个可以直接解码 Base64 和 Base64URL 的函数,无需任何其他依赖。
const PADCHAR = '=';
const B64index = [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0,62,63,62,62,63,52,53,54,55,56,57,58,59,60,61, 0, 0,
0, 0, 0, 0, 0, 0, 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, 0, 0, 0, 0,63, 0,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];
function b64decode(s) {
const len = s.length;
if (len === 0) return s;
const padding = (s.charAt(len-1) === PADCHAR);
const pad = padding || ((len % 4) > 0);
const L = (Math.floor((len+3)/4)-pad)*4;
var x = [];
for (i = 0; i < L; i += 4)
{
var n = B64index[s.charCodeAt(i)] << 18 |
B64index[s.charCodeAt(i+1)] << 12 |
B64index[s.charCodeAt(i+2)] << 6 |
B64index[s.charCodeAt(i+3)];
x.push(String.fromCharCode(n >> 16, (n >> 8) & 0xff, n & 0xff));
}
if (pad)
{
var n = B64index[s.charCodeAt(L)] << 18 |
B64index[s.charCodeAt(L+1)] << 12;
x.push(String.fromCharCode(n >> 16));
if (len > L + 2 && ((s.charAt(L+2) != PADCHAR) || !padding))
{
n |= B64index[s.charCodeAt(L+2)] << 6;
x.push(String.fromCharCode((n >> 8) & 0xff));
}
}
return x.join('');
}
为了使用此函数来解码 Base64URL 字符串,我使用 JWT 令牌作为示例。首先,我分割了令牌。然后,我解码 JWT 有效负载,然后将其解析为 JSON 对象。
const elements = token.split('.');
const payload = JSON.parse(b64decode(elements[1]));
var str = "string";
var encoded = btoa(str); // encode a string (base64)
var decoded = atob(encoded); //decode the string
alert( ["string base64 encoded:",encoded,"\r\n", "string base64 decoded:",decoded].join('') );