我对使用 SOAP 进行 NetSuite 调用这一领域还不熟悉。因此,我对如何解决问题的思考可能完全错误。这是我试图解决的问题: - 语言:Python+Zeep - 我想将我的应用程序从电子邮件传递转移到基于令牌的身份验证。
在 Python 中,我能够生成 TokenPassport 的所有参数。 这是我感到困惑的地方:我在堆栈上查找了一些代码,发现人们正在使用 client.service.login() 方法来登录。此方法采用护照而不是 tokenpassport 对象。 是否有一个单独的方法可以使用 tokenpassport obj 进行登录?或者我是否需要使用参数生成(硬编码)一个 XML,并将其作为数据传入标头?
谢谢 T
希望下面的代码可以帮助刚入门的人。
base = '&'.join([nsAccountID, consumerKey, token, Nonce, currentTime])
key = '&'.join([consumerSecret, tokenSecret])
digest = hmac.new(str.encode(key), msg=str.encode(base), digestmod=hashlib.sha256).digest()
signature = base64.b64encode(digest).decode()
tokenPassport = client.get_type('ns0:TokenPassport')
PassportSignature = client.get_type('ns0:TokenPassportSignature')
tokenPassportSignature = PassportSignature(signature, "HMAC-SHA256" )
clientPass = tokenPassport(account=nsAccountId, consumerKey = consumerKey, token= token, nonce= Nonce, timestamp=currentTime, signature=tokenPassportSignature)
search = client.get_type('ns5:ItemSearchBasic')
searchCriteriaComplex = client.get_type('ns0:SearchStringField')
searchCriteria = searchCriteriaComplex(searchValue= "Test Display Name - tax", operator="is")
searchItem = search(displayName = searchCriteria)
testRes = client.service.search(searchRecord= searchItem, _soapheaders={"tokenPassport": clientPass})
我没有对此进行更深入的研究,而是尝试了 netsuite,这要好得多。
这是我生成 TokenPassport 的方法。
def _generateTimestamp(self):
return str(int(time()))
def _generateNonce(self, length=20):
"""Generate pseudorandom number
"""
return ''.join([str(random.randint(0, 9)) for i in range(length)])
def _getSignatureMessage(self, nonce, timestamp):
return '&'.join(
(
self._setting['ACCOUNT'],
self._setting['CONSUMER_KEY'],
self._setting['TOKEN_ID'],
nonce,
timestamp,
)
)
def _getSignatureKey(self):
return '&'.join((self._setting['CONSUMER_SECRET'], self._setting['TOKEN_SECRET']))
def _getSignatureValue(self, nonce, timestamp):
key = self._getSignatureKey()
message = self._getSignatureMessage(nonce, timestamp)
hashed = hmac.new(
key=key.encode('utf-8'),
msg=message.encode('utf-8'),
digestmod=hashlib.sha256
).digest()
return base64.b64encode(hashed).decode()
@property
def tokenPassport(self):
TokenPassport = self.getDataType("ns0:TokenPassport")
TokenPassportSignature = self.getDataType("ns0:TokenPassportSignature")
nonce = self._generateNonce()
timestamp = self._generateTimestamp()
tokenPassportSignature = TokenPassportSignature(
self._getSignatureValue(nonce, timestamp),
algorithm='HMAC-SHA256'
)
return TokenPassport(
account=self._setting['ACCOUNT'],
consumerKey=self._setting['CONSUMER_KEY'],
token=self._setting['TOKEN_ID'],
nonce=nonce,
timestamp=timestamp,
signature=tokenPassportSignature
)
Zeep 很棒 - 但我想要一个在客户端内指定命名空间或替代查找的选项。但这是当前(2023 年)使用 zeep 访问 Netsuite 的方式,并需要修改服务地址。
def createNonce(length=20):
return ''.join([str(random.randint(0, 9)) for i in range(length)])
def createSignature(passport, tokenSecret, consumerSecret):
signatureKey = f"{urllib.parse.quote_plus(consumerSecret)}&{urllib.parse.quote_plus(tokenSecret)}"
baseString = f"{passport.account}&{passport.consumerKey}&{passport.token}&{passport.nonce}&{passport.timestamp}"
return base64.b64encode(hmac.digest(signatureKey.encode('utf-8'), baseString.encode('utf-8'), hashlib.sha256))
--------------------------------------------------------------------------------------
client = zeep.CachingClient(wsdl=netsuiteWSDL)
client.service._binding_options["address"] = (nsURL + nsURLPath)
#service = client.create_service(netsuiteBinding, address = (nsURL + nsURLPath) )
TokenPassport = client.get_type("ns0:TokenPassport");
tokenPassport = TokenPassport(
account = nsAccount,
consumerKey = consumerKey,
token = tokenKey,
nonce = createNonce(),
timestamp = str(int(datetime.now().timestamp()))
)
TokenPassportSignature = client.get_type("ns0:TokenPassportSignature")
hashAlgorithm = "HMAC-SHA256"
tokenPassport["signature"] = TokenPassportSignature(createSignature(tokenPassport, tokenSecret, consumerSecret), hashAlgorithm)
RecordType = client.get_type("ns1:RecordType")
RecordRef = client.get_type("ns0:RecordRef")
recordRef = RecordRef(
internalId = "14764193",
type = RecordType("customer")
)
print(client.service.get(recordRef, _soapheaders = { "tokenPassport": tokenPassport } ))
可能有多种方法可以利用自动绑定,但我喜欢清晰。具有讽刺意味的是,因为我不想在命名空间中搜索类型和方法。