使用 Python 应用程序 (访问)

此示例演示如何调用外部 Python 脚本以获取 OAuth2 令牌。 身份验证委托的实现需要有效的 OAuth2 访问令牌。

先决条件

运行下面的示例:

  • 安装 Python 2.7 或更高版本。
  • 在项目中实现 utils.h/cpp。
  • Auth.py 添加到项目,并存在于生成时二进制文件的同一目录中。
  • 完成 (MIP) SDK 安装和配置。 除其他任务外,还会在租户中注册Azure Active Directory (Azure AD) 应用程序。 Azure AD将提供一个应用程序 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 的 ADAL 直接获取身份验证令牌。 此代码仅作为获取身份验证令牌供示例应用使用的方式包含在内,不用于生产。 该脚本仅适用于支持普通旧用户名/密码 http 身份验证的租户。 MFA 或基于证书的身份验证将失败。

注意

在运行此示例之前,必须通过运行以下命令之一来安装 ADAL for Python:

pip install adal
pip3 install adal
import getopt
import sys
import json
import re
from adal import AuthenticationContext

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)

  # Find everything after the last '/' and replace it with 'token'
  if not authority.endswith('token'):
    regex = re.compile('^(.*[\/])')
    match = regex.match(authority)
    authority = match.group()
    authority = authority + username.split('@')[1]

  auth_context = AuthenticationContext(authority)
  token = auth_context.acquire_token_with_username_password(resource, username, password, clientId)
  print(token["accessToken"])

if __name__ == '__main__':
  main(sys.argv[1:])

更新 AcquireOAuth2Token

最后,更新 AcquireOAuth2Token 中的 函数 AuthDelegateImpl 以调用重载 AcquireToken 的函数。 资源和颁发机构 URL 通过读取 和 challenge.GetResource() 获取 challenge.GetAuthority()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 将调用"AcquireOAuth2Token 函数,传递质询,执行 Python 脚本,接收令牌,然后将令牌呈现 engine 给服务。