获取访问令牌 (Python)
此示例演示了如何通过调用外部 Python 脚本来获取 OAuth2 令牌。 身份验证委托的实现需要有效的 OAuth2 访问令牌。
先决条件
若要运行该示例:
- 安装 Python 3.10 或更高版本。
- 在项目中实现 utils.h/cpp。
- Auth.py 应添加到项目中,并与生成时的二进制文件存在同一个目录中。
- 完成 Microsoft 信息保护 (MIP) SDK 设置和配置。 除其他任务外,在 Microsoft Entra 租户中注册客户端应用程序。 Microsoft Entra ID 提供应用程序 ID,也称为客户端 ID,用于令牌获取逻辑。
此代码不用于生产用途。 它只用于开发和理解身份验证概念。 此示例是跨平台的。
sample::auth::AcquireToken()
在这个简单的身份验证示例中,我们演示了一个简单的 AcquireToken()
函数,该函数不接受任何参数,并返回一个硬编码令牌值。 在此示例中,我们将重载 AcquireToken()以接受身份验证参数并调用外部 Python 脚本来返回令牌。
auth.h
在 auth.h 中将会重载 AcquireToken()
,并且重载后的函数和更新后的参数如下所示:
//auth.h
#include <string>
namespace sample {
namespace auth {
std::string AcquireToken(
const std::string& userName, //A string value containing the user's UPN.
const std::string& password, //The user's password in plaintext
const std::string& clientId, //The Azure AD client ID (also known as Application ID) of your application.
const std::string& resource, //The resource URL for which an OAuth2 token is required. Provided by challenge object.
const std::string& authority); //The authentication authority endpoint. Provided by challenge object.
}
}
前三个参数由用户输入或硬编码提供给应用程序。 最后两个参数由 SDK 提供给身份验证委派。
auth.cpp
在 auth.cpp 中,我们会添加重载后函数的定义,然后定义调用 Python 脚本所需的代码。 该函数接受所有提供的参数,并将这些参数传递给 Python 脚本。 该脚本将会执行并返回字符串格式的令牌。
#include "auth.h"
#include "utils.h"
#include <fstream>
#include <functional>
#include <memory>
#include <string>
using std::string;
using std::runtime_error;
namespace sample {
namespace auth {
//This function implements token acquisition in the application by calling an external Python script.
//The Python script requires username, password, clientId, resource, and authority.
//Username, Password, and ClientId are provided by the user/developer
//Resource and Authority are provided as part of the OAuth2Challenge object that is passed in by the SDK to the AuthDelegate.
string AcquireToken(
const string& userName,
const string& password,
const string& clientId,
const string& resource,
const string& authority) {
string cmd = "python";
if (sample::FileExists("auth.py"))
cmd += " auth.py -u ";
else
throw runtime_error("Unable to find auth script.");
cmd += userName;
cmd += " -p ";
cmd += password;
cmd += " -a ";
cmd += authority;
cmd += " -r ";
cmd += resource;
cmd += " -c ";
// Replace <application-id> with the Application ID provided during your Azure AD application registration.
cmd += (!clientId.empty() ? clientId : "<application-id>");
string result = sample::Execute(cmd.c_str());
if (result.empty())
throw runtime_error("Failed to acquire token. Ensure Python is installed correctly.");
return result;
}
}
}
Python Script
此脚本直接通过 适用于 Python 的 Microsoft 身份验证库 (MSAL) 获取身份验证令牌。 此代码仅作为获取身份验证令牌以供示例应用使用的方法包含在内,不用于生产。 该脚本仅适用于支持纯旧用户名/密码身份验证的租户。 此脚本不支持 MFA 或基于证书的身份验证。
注意
在运行此示例之前,必须通过运行以下命令之一安装适用于 Python 的 MSAL:
pip install msal
pip3 install msal
import getopt
import sys
import json
import re
from msal import PublicClientApplication
def printUsage():
print('auth.py -u <username> -p <password> -a <authority> -r <resource> -c <clientId>')
def main(argv):
try:
options, args = getopt.getopt(argv, 'hu:p:a:r:c:')
except getopt.GetoptError:
printUsage()
sys.exit(-1)
username = ''
password = ''
authority = ''
resource = ''
clientId = ''
for option, arg in options:
if option == '-h':
printUsage()
sys.exit()
elif option == '-u':
username = arg
elif option == '-p':
password = arg
elif option == '-a':
authority = arg
elif option == '-r':
resource = arg
elif option == '-c':
clientId = arg
if username == '' or password == '' or authority == '' or resource == '' or clientId == '':
printUsage()
sys.exit(-1)
# ONLY FOR DEMO PURPOSES AND MSAL FOR PYTHON
# This shouldn't be required when using proper auth flows in production.
if authority.find('common') > 1:
authority = authority.split('/common')[0] + "/organizations"
app = PublicClientApplication(client_id=clientId, authority=authority)
result = None
if resource.endswith('/'):
resource += ".default"
else:
resource += "/.default"
# *DO NOT* use username/password authentication in production system.
# Instead, consider auth code flow and using a browser to fetch the token.
result = app.acquire_token_by_username_password(username=username, password=password, scopes=[resource])
print(result['access_token'])
if __name__ == '__main__':
main(sys.argv[1:])
更新 AcquireOAuth2Token
最后,更新 AuthDelegateImpl
中的 AcquireOAuth2Token
函数以调用重载后的 AcquireToken
函数。 通过读取 challenge.GetResource()
和 challenge.GetAuthority()
来获取资源和颁发机构 URL。 OAuth2Challenge
将会在添加引擎时传入身份验证委派。 此工作由 SDK 完成,无需在开发人员的一部分执行额外的工作。
bool AuthDelegateImpl::AcquireOAuth2Token(
const mip::Identity& /*identity*/,
const OAuth2Challenge& challenge,
OAuth2Token& token) {
//call our AcquireToken function, passing in username, password, clientId, and getting the resource/authority from the OAuth2Challenge object
string accessToken = sample::auth::AcquireToken(mUserName, mPassword, mClientId, challenge.GetResource(), challenge.GetAuthority());
token.SetAccessToken(accessToken);
return true;
}
engine
添加后,SDK 将调用“AcquireOAuth2Token”函数,传入质询,执行 Python 脚本,接收令牌,然后将令牌呈现给服务。