问题描述

使用Azure Identity,根据指定的客户端凭据获取Access Token中,先后遇见了

  • “ValueError: "get_token" requires at least one scope”
  • “ClientSecretCredential.get_token failed: Authentication failed: sequence item 0: expected str instance, list found”

最初的Python 代码如下:

from azure.identity import ClientSecretCredential,AzureAuthorityHosts  
from azure.mgmt.resource import SubscriptionClient  

# Service principal credentials for Azure
credential = ClientSecretCredential(tenant_id="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", client_id="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", client_secret="xxxxxxxxxxxx.xxxx")

access_token = credential.get_token(scopes=["https://management.chinacloudapi.cn/.default"])
print(access_token)

 

问题解答

第一个问题: get_token 的至少需要一个 scope参数

【Azure Developer】Python – Get Access Token by Azure Identity in China Azure Environment_Azure

以上代码按照python常规的方式,为传递的参数指定参数名,根据ClientSecretCredential get_token方法介绍,参数名就是 scopes 。

【Azure Developer】Python – Get Access Token by Azure Identity in China Azure Environment_Azure_02

在没有想明白的情况下,最后去掉了指定参数名,直接传入值。问题一消失,问题二产生。

【Azure Developer】Python – Get Access Token by Azure Identity in China Azure Environment_Python_03

第二个问题:get_token方法失败,参数传递序列中,第一个参数期待的是一个str,但是发现是一个list。

ClientSecretCredential.get_token failed: Authentication failed: sequence item 0: expected str instance, list found

这里是一个copy错误,scopes参数从其它代码中复制过来。并没有仔细对比这里的get_token需要传递的不是数组([]), 而是一个字符串(str)。把第一个参数修改为字符串后。成功获取到Access Token。

正确的完整Python 代码

from azure.identity import ClientSecretCredential,AzureAuthorityHosts  
from azure.mgmt.resource import SubscriptionClient  

# Service principal credentials for Azure
credential = ClientSecretCredential(tenant_id="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", client_id="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", client_secret="xxxxxxxxxxxx.xxxx")

access_token = credential.get_token("https://management.chinacloudapi.cn/.default")

print(access_token)

 

附录:理解target=" ".join(target)

错误消息:

…\site-packages\msal\token_cache.py", line 103, in _get_access_token

    target=" ".join(target),

TypeError: sequence item 0: expected str instance, list found

源代码:

… …

        return self._get(

            self.CredentialType.ACCESS_TOKEN,

            self.key_makers[TokenCache.CredentialType.ACCESS_TOKEN](

                home_account_id=home_account_id,

                envirnotallow=environment,

                client_id=client_id,

                realm=realm,

                target=" ".join(target),

                ),

            default=default)

测试:

print(" ".join(["Hello","World",", This is join method test." ]))

 

输出:

Hello World , This is join method test.

 

说明:

在Python中," ".join(target)这段代码的作用是将target序列中的元素通过指定的分隔符(这里是空格)连接成一个新的字符串。

例如,如果target是['Hello', 'World'],那么" ".join(target)的结果将是'Hello World'。

这个方法通常用于将多个字符串片段合并成一个完整的字符串。

 

 

[END]

 


当在复杂的环境中面临问题,格物之道需:浊而静之徐清,安以动之徐生。 云中,恰是如此!