React Native对接WordPress OAuth1签名验证失败求助
让我们一步步排查你的问题,先解决之前的「Consumer Key is invalid」错误,再搞定核心的「OAuth signature does not match」问题:
首先解决「Consumer Key is invalid」的问题
你之前的Authorization头格式存在两个不符合OAuth 1.0规范的问题:
- OAuth参数之间需要用逗号加空格分隔,而非单纯的逗号(服务器解析时可能会把参数连在一起,导致consumer key识别错误)
- OAuth参数的值需要用双引号包裹(规范要求的格式)
修正后的Authorization头开头示例:
"Authorization": "OAuth oauth_consumer_key=\"ieQCM48wXWuW\", oauth_signature_method=\"HMAC-SHA1\", oauth_timestamp=\"123456789\", oauth_nonce=\"FFeySWNH1Am\", oauth_version=\"1.0\", oauth_signature=\"你的正确签名\""
核心问题:「OAuth signature does not match」的原因及解决方法
签名不匹配几乎都是因为基字符串、签名密钥、签名编码格式三者之一不符合规范,我们逐个拆解修复:
1. 确保基字符串与请求参数完全一致
你的代码里存在一个致命的不一致:
- Authorization头里的
oauth_nonce是FFeySWNH1Am - 但生成签名用的基字符串里
oauth_nonce是nonce
这直接导致签名与实际请求参数不匹配,服务器验证必然失败。生成基字符串时,必须保证所有OAuth参数(包括nonce、timestamp)与请求头里的内容完全一致。
另外,基字符串的构造必须严格遵循以下规则:
- 开头是大写的HTTP方法(比如
POST) - 第二部分是URL编码后的完整请求URL(必须和fetch的URL完全一致,包括协议、域名、路径)
- 第三部分是URL编码后的所有OAuth参数串:
- 先把所有OAuth参数(除了
oauth_signature本身)按字典序排序 - 每个参数的键和值分别做URL编码(遵循RFC 3986,用
%20代替空格,不要用+) - 用
&连接所有编码后的键值对
- 先把所有OAuth参数(除了
- 三部分用
&连接,不要用HTML转义的&,必须用原始的&
针对你的请求,正确的基字符串应该是:
POST&http%3A%2F%2Fauth-test-site.azurewebsites.net%2Foauth1%2Frequest&oauth_consumer_key%3DieQCM48wXWuW&oauth_nonce%3DFFeySWNH1Am&oauth_signature_method%3DHMAC-SHA1&oauth_timestamp%3D123456789&oauth_version%3D1.0
2. 使用正确的签名密钥
HMAC-SHA1的签名密钥规则是:consumer_secret&token_secret
- 在请求令牌(request token)阶段,你还未获取到access token,所以
token_secret是空字符串,因此密钥必须是你的consumer_secret&(注意末尾的&不能省略)
你的consumer secret是9Yf0HG8RWrk0a4IKxwnkK2LUvd15NNF0b98jZwpOmQhoO7vv,所以签名密钥为:
9Yf0HG8RWrk0a4IKxwnkK2LUvd15NNF0b98jZwpOmQhoO7vv&
3. 用正确格式生成签名
OAuth 1.0要求签名是HMAC-SHA1哈希的Base64编码结果,而非十六进制字符串!你之前用在线工具生成的是十六进制值(5c6f358b1086cf2387e46a6c00e412fcfc2a4743),这不符合规范,必须转成Base64。
你可以用JavaScript直接生成正确签名,避免依赖在线工具:
Node.js环境:
const crypto = require('crypto'); const baseString = 'POST&http%3A%2F%2Fauth-test-site.azurewebsites.net%2Foauth1%2Frequest&oauth_consumer_key%3DieQCM48wXWuW&oauth_nonce%3DFFeySWNH1Am&oauth_signature_method%3DHMAC-SHA1&oauth_timestamp%3D123456789&oauth_version%3D1.0'; const consumerSecret = '9Yf0HG8RWrk0a4IKxwnkK2LUvd15NNF0b98jZwpOmQhoO7vv'; const signingKey = `${consumerSecret}&`; const signature = crypto.createHmac('sha1', signingKey) .update(baseString) .digest('base64'); console.log(signature); // 这就是你需要的oauth_signature值
浏览器环境(Web Crypto API):
async function generateSignature(baseString, signingKey) { const encoder = new TextEncoder(); const keyData = encoder.encode(signingKey); const baseStringData = encoder.encode(baseString); const key = await crypto.subtle.importKey( 'raw', keyData, { name: 'HMAC', hash: 'SHA-1' }, false, ['sign'] ); const signatureBuffer = await crypto.subtle.sign('HMAC', key, baseStringData); return btoa(String.fromCharCode(...new Uint8Array(signatureBuffer))); } // 调用示例 generateSignature( 'POST&http%3A%2F%2Fauth-test-site.azurewebsites.net%2Foauth1%2Frequest&oauth_consumer_key%3DieQCM48wXWuW&oauth_nonce%3DFFeySWNH1Am&oauth_signature_method%3DHMAC-SHA1&oauth_timestamp%3D123456789&oauth_version%3D1.0', '9Yf0HG8RWrk0a4IKxwnkK2LUvd15NNF0b98jZwpOmQhoO7vv&' ).then(signature => { console.log(signature); });
4. 修正后的完整请求代码
整合所有修正点后,你的fetch请求应该是这样的:
const url = 'http://auth-test-site.azurewebsites.net/oauth1/request'; const oauthNonce = 'FFeySWNH1Am'; const oauthTimestamp = '123456789'; const consumerKey = 'ieQCM48wXWuW'; const consumerSecret = '9Yf0HG8RWrk0a4IKxwnkK2LUvd15NNF0b98jZwpOmQhoO7vv'; // 构造基字符串 const encodedUrl = encodeURIComponent(url); const params = [ `oauth_consumer_key=${encodeURIComponent(consumerKey)}`, `oauth_nonce=${encodeURIComponent(oauthNonce)}`, `oauth_signature_method=${encodeURIComponent('HMAC-SHA1')}`, `oauth_timestamp=${encodeURIComponent(oauthTimestamp)}`, `oauth_version=${encodeURIComponent('1.0')}` ].sort().join('&'); const encodedParams = encodeURIComponent(params); const baseString = `POST&${encodedUrl}&${encodedParams}`; // 生成签名(这里用Node.js示例,浏览器环境替换为Web Crypto函数) const crypto = require('crypto'); const signingKey = `${consumerSecret}&`; const oauthSignature = crypto.createHmac('sha1', signingKey) .update(baseString) .digest('base64'); fetch(url, { method: "POST", headers: { "Accept": "application/json", "Content-Type": "application/x-www-form-urlencoded", "Authorization": `OAuth oauth_consumer_key="${consumerKey}", oauth_signature_method="HMAC-SHA1", oauth_timestamp="${oauthTimestamp}", oauth_nonce="${oauthNonce}", oauth_version="1.0", oauth_signature="${oauthSignature}"` }, credentials: "same-origin" }) .then(response => response.text()) .then(text => console.log(text)) .catch(error => console.error(error.message));
额外注意事项
- 生产环境不要硬编码nonce和timestamp:nonce应该是每次请求唯一的随机字符串,timestamp应该是当前的Unix时间戳(秒数),否则服务器可能会拒绝重复请求。
- 确保所有URL编码严格遵循RFC 3986:比如
!、*、()这些字符也要编码,不要只编码空格和常见特殊符号。
内容的提问来源于stack exchange,提问作者Arvind Ramaswami
相关产品推荐
相关产品推荐

