此範例示範如何呼叫外部 Python 腳本以取得 OAuth 2.0 令牌。 認證代理實作需要有效的 OAuth 2.0 存取權杖。
先決條件
若要執行範例:
- 安裝 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 指令碼
此指令碼會使用 適用於 Python 的 Microsoft 驗證資源庫(MSAL) 直接取得驗證權杖。 此程式碼僅用於取得驗證令牌以供範例應用程式使用,並非用於生產環境。 這個腳本只對支援使用者名/密碼認證的租戶有效。 此腳本不支援多重驗證(MFA)或憑證式驗證。
Note
在執行此範例前,請先執行以下指令之一安裝 MSAL for Python:
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
最後,更新 AcquireOAuth2Token 中的 AuthDelegateImpl 函式,以呼叫多載的 AcquireToken 函式。 請閱讀 challenge.GetResource() 並 challenge.GetAuthority() 取得資源與權威網址。 SDK 在加入引擎時,會將 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;
}
當 SDK 加入 engine時,它會呼叫 函 AcquireOAuth2Token 式。 函式會傳遞挑戰,執行 Python 腳本,接收一個權杖,並將該權杖呈現給服務。