Bunny.net CDN令牌认证对.m3u8文件失效问题求助
问题:HLS播放列表URL签名后返回403错误,但缩略图URL正常
我正在实现基于HTTP Live Streaming (HLS)的视频流方案,用Node.js给HLS播放列表URL签名时,使用的是CDN管理界面「Stream > Security > Token Authentication Key」区域获取的密钥。
但按照指定流程完成签名后,访问.m3u8播放列表URL时始终返回HTTP 403禁止错误。奇怪的是,将相同的签名流程应用到视频缩略图(如thumbnail.jpg)的URL上时,却能正常访问文件——这说明令牌生成和认证流程本身是有效的。
已尝试的解决措施:
- 改用「CDN > Security > Token Authentication Key」区域的Token Authentication Key
- 切换到CDN令牌认证(基础版),但仍只有缩略图可正常访问,.m3u8文件依旧返回403
以下是对thumbnail.jpg有效但对playlist.m3u8无效的两段代码:
var crypto = require('crypto'), securityKey = 'key_from_stream_security', path = '/a1640499-52ef-4721-9ba9-4e659cada6f5/playlist.m3u8'; // 设置过期时间为4天后 var expires = 1688885053; var hashableBase = securityKey + path + expires; // 生成并编码令牌 var md5String = crypto.createHash('md5').update(hashableBase).digest('binary'); var token = new Buffer(md5String, 'binary').toString('base64'); token = token.replace(/\+/g, '-').replace(/\//g, '_').replace(/\=/g, ''); // 生成最终URL var url = 'https://vz-9ac10aa0-92d.b-cdn.net' + path + '?token=' + token + '&expires=' + expires; console.log(url);
var queryString = require('querystring'); var crypto = require('crypto'); var URL = require('url').URL; // 引入URL构造器 function addCountries(url, a, b) { var tempUrl = url; if (a != null) { var tempUrlOne = new URL(tempUrl); tempUrl += (tempUrlOne.search == '' ? '?' : '&') + 'token_countries=' + a; } if (b != null) { var tempUrlTwo = new URL(tempUrl); tempUrl += (tempUrlTwo.search == '' ? '?' : '&') + 'token_countries_blocked=' + b; } return tempUrl; } function signUrl( url, securityKey, expirationTime = 3600, userIp, isDirectory = false, pathAllowed, countriesAllowed, countriesBlocked, ) { /* url: 不带末尾斜杠的CDN URL - 示例: http://test.b-cdn.net/file.png securityKey: 拉取区域中找到的安全令牌 expirationTime: 认证有效期(默认: 86400秒/24小时) userIp: 若启用用户IP功能则为可选参数 isDirectory: 可选参数 - 设为"true"时返回用斜杠分隔的URL(示例: (domain)/bcdn_token=...) pathAllowed: 要认证的目录(示例: /path/to/images) countriesAllowed: 允许访问的国家列表(示例: CA, US, TH) countriesBlocked: 禁止访问的国家列表(示例: CA, US, TH) */ var parameterData = '', parameterDataUrl = '', signaturePath = '', hashableBase = '', token = ''; var expires = expirationTime; var url = addCountries(url, countriesAllowed, countriesBlocked); var parsedUrl = new URL(url); var parameters = new URL(url).searchParams; if (pathAllowed != '') { signaturePath = pathAllowed; parameters.set('token_path', signaturePath); } else { signaturePath = decodeURIComponent(parsedUrl.pathname); } console.log(parsedUrl.pathname); parameters.sort(); if (Array.from(parameters).length > 0) { parameters.forEach(function (value, key) { if (value == '') { return; } if (parameterData.length > 0) { parameterData += '&'; } parameterData += key + '=' + value; parameterDataUrl += '&' + key + '=' + queryString.escape(value); }); } hashableBase = securityKey + signaturePath + expires + (userIp != null ? userIp : '') + parameterData; token = Buffer.from( crypto.createHash('sha256').update(hashableBase).digest(), ).toString('base64'); token = token .replace(/\n/g, '') .replace(/\+/g, '-') .replace(/\//g, '_') .replace(/=/g, ''); if (isDirectory) { return ( parsedUrl.protocol + '//' + parsedUrl.host + '/bcdn_token=' + token + parameterDataUrl + '&expires=' + expires + parsedUrl.pathname ); } else { return ( parsedUrl.protocol + '//' + parsedUrl.host + parsedUrl.pathname + '?token=' + token + parameterDataUrl + '&expires=' + expires ); } } console.log( signUrl( 'https://vz-9ac10aa0-92d.b-cdn.net/548789ea-d0d7-4dac-b656-cc2acedf0f5c/playlist.m3u8', 'key_from_stream_security', 1688885053, '', false, '/548789ea-d0d7-4dac-b656-cc2acedf0f5c/playlist.m3u8', ), );
内容的提问来源于stack exchange,提问作者Ghayoor ul Haq
相关产品推荐
相关产品推荐

