You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在VB.NET中将NetSuite RestLet认证从SHA1改为SHA256

VB.NET 对接NetSuite OAuth HMAC-SHA256签名实现方案

现存问题说明

  • 旧应用基于VB.NET开发,对接Oracle NetSuite发送JSON数据,原OAuth1.0签名采用HMAC-SHA1算法,需升级为HMAC-SHA256
  • 跨语言参考实现转换后失效,原有SHA1版本业务代码如下:
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 Or SecurityProtocolType.Tls11 Or SecurityProtocolType.Tls
Dim url As New Uri("https://xxxxxx.restlets.api.netsuite.com/app/site/hosting/restlet.nl?script=999&deploy=1")
Dim timestamp = OAuthBase.GenerateTimeStamp()
Dim nonce = OAuthBase.GenerateNonce()
Dim ckey = "01234" '//Consumer Key
Dim csecret = "56789" '// Consumer Secret
Dim tkey = "43210" '// Token ID
Dim tsecret = "98765" '// Token Secret

Dim Signature = OAuthBase.GenerateSignature(url, ckey, csecret, tkey, tsecret, "POST", timestamp, nonce)
If (Signature.Contains("+")) Then
    Signature = Signature.Replace("+", "%3D")
End If
Dim header As String = "Authorization: OAuth "
header += "oauth_signature=""" & Signature & ""","
header += "oauth_version=""1.0"","
header += "oauth_nonce=""" & nonce & ""","
header += "oauth_signature_method=""HMAC-SHA1"","
header += "oauth_consumer_key=""" & ckey & ""","
header += "oauth_token=""" & tkey & ""","
header += "oauth_timestamp=""" & timestamp & ""","
header += "realm=""xxxxxx"""
  • 原有代码存在两个核心错误:
    • 自定义OAuthBase类内部哈希逻辑固定为HMAC-SHA1,仅修改请求头里的oauth_signature_method字段不会改变实际签名计算结果
    • 单独替换+为%3D的编码逻辑不符合OAuth1.0的RFC3986编码规范,会直接导致签名校验失败

正确实现代码

第一步:替换OAuthBase核心签名逻辑

保留原有GenerateTimeStamp、GenerateNonce方法不变,将签名计算逻辑替换为HMAC-SHA256实现,同时修正编码逻辑,完整核心类代码如下:

Imports System
Imports System.Collections.Specialized
Imports System.Security.Cryptography
Imports System.Text
Imports System.Web

Public Class OAuthBase
    Public Shared Function GenerateSignature(url As Uri, consumerKey As String, consumerSecret As String, tokenKey As String, tokenSecret As String, method As String, timeStamp As String, nonce As String) As String
        ' 1. 构造签名基串
        Dim signatureBase As New StringBuilder()
        signatureBase.Append(method.ToUpper() & "&")
        signatureBase.Append(UrlEncode(url.GetLeftPart(UriPartial.Path)) & "&")
        
        ' 收集所有需要参与签名的参数
        Dim parameters As New NameValueCollection()
        parameters.Add("oauth_consumer_key", consumerKey)
        parameters.Add("oauth_nonce", nonce)
        parameters.Add("oauth_signature_method", "HMAC-SHA256")
        parameters.Add("oauth_timestamp", timeStamp)
        parameters.Add("oauth_token", tokenKey)
        parameters.Add("oauth_version", "1.0")
        ' 加入URL查询参数
        Dim queryParams = HttpUtility.ParseQueryString(url.Query)
        For Each key As String In queryParams.AllKeys
            parameters.Add(key, queryParams(key))
        Next

        ' 参数按字典序排序后拼接
        Dim sortedParams = From key In parameters.AllKeys Order By key Select $"{UrlEncode(key)}={UrlEncode(parameters(key))}"
        signatureBase.Append(UrlEncode(String.Join("&", sortedParams)))

        ' 2. 构造签名密钥
        Dim signatureKey = $"{UrlEncode(consumerSecret)}&{UrlEncode(tokenSecret)}"

        ' 3. 用HMAC-SHA256计算签名
        Using hmac As New HMACSHA256(Encoding.ASCII.GetBytes(signatureKey))
            Dim hashBytes = hmac.ComputeHash(Encoding.ASCII.GetBytes(signatureBase.ToString()))
            ' 转Base64后做标准URL编码
            Return UrlEncode(Convert.ToBase64String(hashBytes))
        End Using
    End Function

    ' RFC3986标准URL编码实现
    Private Shared Function UrlEncode(value As String) As String
        Return Uri.EscapeDataString(value)
            .Replace("!", "%21")
            .Replace("'", "%27")
            .Replace("(", "%28")
            .Replace(")", "%29")
            .Replace("*", "%2A")
    End Function

    ' 原有时间戳、随机串生成方法保持不变即可
    Public Shared Function GenerateTimeStamp() As String
        Return CType((DateTime.UtcNow - New DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc)).TotalSeconds, Int64).ToString()
    End Function

    Public Shared Function GenerateNonce() As String
        Return Guid.NewGuid().ToString("N")
    End Function
End Class

第二步:修正业务调用代码

删除原有错误的+符号替换逻辑,修改签名方法标识为HMAC-SHA256,修正后调用代码如下:

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12
Dim url As New Uri("https://xxxxxx.restlets.api.netsuite.com/app/site/hosting/restlet.nl?script=999&deploy=1")
Dim timestamp = OAuthBase.GenerateTimeStamp()
Dim nonce = OAuthBase.GenerateNonce()
Dim ckey = "01234" ' Consumer Key
Dim csecret = "56789" ' Consumer Secret
Dim tkey = "43210" ' Token ID
Dim tsecret = "98765" ' Token Secret

' 直接获取已经完成标准编码的签名,不需要额外替换字符
Dim Signature = OAuthBase.GenerateSignature(url, ckey, csecret, tkey, tsecret, "POST", timestamp, nonce)

Dim header As New StringBuilder("OAuth ")
header.Append($"oauth_signature=""{Signature}"",")
header.Append("oauth_version=""1.0"",")
header.Append($"oauth_nonce=""{nonce}"",")
header.Append("oauth_signature_method=""HMAC-SHA256"",")
header.Append($"oauth_consumer_key=""{ckey}"",")
header.Append($"oauth_token=""{tkey}"",")
header.Append($"oauth_timestamp=""{timestamp}"",")
header.Append("realm=""xxxxxx""")

' 给请求添加头时不需要带"Authorization: "前缀,直接赋值给请求对象的Authorization头即可
' request.Headers("Authorization") = header.ToString()

注意事项

  • NetSuite的OAuth校验严格区分大小写,所有参数名、签名方法字符串必须完全匹配
  • 时间戳必须是UTC时间的秒级时间戳,不能使用本地时间
  • 所有参与签名的参数不能遗漏,包括URL路径上的query参数、POST表单提交的参数;如果是JSON body提交则body内容不需要参与签名
  • Tls1.1和Tls协议已经存在安全风险,直接指定Tls1.2即可,不需要兼容低版本

内容的提问来源于stack exchange,提问作者Ashraf

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.01 23:39:36