Получить токены

Существует множество способов получить токен с использованием MSAL Python. Некоторые требуют взаимодействия с пользователем, а другие — нет. Подход, используемый для получения маркера, отличается в зависимости от того, создает ли разработчик общедоступный клиент (классический или мобильный) или конфиденциальное клиентское приложение (веб-приложение, веб-API или управляющая программа, например служба Windows).

Необходимые условия

Прежде чем получать маркеры с помощью MSAL Python, узнайте о типах клиентского приложения.

Получение учетной записи пользователя

Приложение может получить токен от собственного имени или от имени пользователя. Чтобы получить маркер от имени пользователя, приложение должно знать учетную запись пользователя. MSAL Python предоставляет метод get_accounts для получения учетной записи пользователя. Этот метод доступен для обоих PublicClientApplication классов и ConfidentialClientApplication классов. Метод возвращает список учетных записей, в которые пользователь ранее входил, то есть существующих в кэше.

accounts = app.get_accounts(username=user.get("preferred_username"))

Учетную запись, выбранную пользователем для входа в систему, впоследствии можно использовать в acquire_token_silent() для поиска её токенов.

Потоки выдачи токенов

Существует несколько потоков аутентификации, которые можно использовать для получения токенов с использованием MSAL Python. Дополнительные сведения об этих потоках см. в документации по платформа удостоверений Майкрософт.

Предупреждение

Всегда используйте MSAL для получения маркеров безопасности и вызова защищенных веб-API в приложениях. Мы не рекомендуем самостоятельно реализовывать логику получения токенов. Эти потоки помогут вам лучше понять, как работают вещи. Если вы защищаете веб-приложение, мы рекомендуем использовать библиотеку identity. Эта библиотека официально не поддерживается Microsoft, но реализует большую часть логики, необходимой для получения токенов в веб-приложениях.

Интерактивный и молчаливый

MSAL Python поддерживает как интерактивное, так и скрытое получение токенов. Интерактивное получение токена требует взаимодействия с пользователем, а тихое получение токена — нет. Общедоступные клиенты обычно требуют взаимодействия с пользователем, а конфиденциальные клиенты используют предварительно подготовленные учетные данные, такие как сертификаты и секреты.

Используйте метод acquire_token_silent_with_error, чтобы получить токен в фоновом режиме. Этот метод находит допустимый маркер доступа из кэша или действительный маркер обновления из кэша, а затем автоматически использует его для активации нового маркера доступа. Если ни одно из этих условий не выполняется, необходимо использовать интерактивный метод, чтобы получить токен.

Если для вашего приложения не важна точная ошибка обновления токена при поиске в кэше токенов, рекомендуется использовать метод acquire_token_silent.

Пример использования этого метода, как показано в следующем фрагменте кода.

if accounts:
    # If so, you could then somehow display these accounts and let end user choose
    chosen = accounts[0]
    result = app.acquire_token_silent(scopes=["your_scope"], account=chosen)
    
    # At this point, you can save you can update your cache if you are using token caching
    # check result variable, if its None then you should interactively acquire a token
    if not result:
        # So no suitable token exists in cache. Let's get a new one from Microsoft Entra.
        result = app.acquire_token_by_one_of_the_actual_method(..., scopes=["User.Read"])
    
    if "access_token" in result:
        access_token = result["access_token"]
    else:
        print(result.get("error"))  
        print(result.get("error_description"))
        print(result.get("correlation_id"))  # You may need this when reporting a bug

Доступно несколько методов для интерактивного получения токенов. То, какой метод следует использовать, зависит от типа разрабатываемого приложения и потока выдачи токена, который применяется в вашем сценарии.

Интерактивное получение токена для публичных клиентов

Общедоступные клиентские приложения не могут безопасно хранить секрет и могут проходить проверку подлинности только пользователя, взаимодействующего с продуктом. MSAL Python предоставляет логику получения токенов для общедоступных приложений через PublicClientApplication. Ниже перечислены различные методы получения токенов, доступные для общедоступных клиентских приложений.

Процесс ввода кода устройства

Поток кода устройства используется для получения маркеров в приложениях, работающих на устройствах, у которых нет доступа к веб-браузеру. Это приложения, известные как приложения без головы. Этот поток предоставляет пользователю URL-адрес и код. Пользователь переходит в веб-браузер на другом устройстве, вводит код и входит в систему. После успешной проверки подлинности Microsoft Entra возвращает токен устройству без браузера.

Сначала вызывается initiate_device_flow метод.

flow = app.initiate_device_flow(scopes=config["scope"])
if "user_code" not in flow:
    raise ValueError(
        "Fail to create device flow. Err: %s" % json.dumps(flow, indent=4))

print(flow["message"])
sys.stdout.flush()  # Some terminal needs this to ensure the message is shown

# Ideally you should wait here, in order to save some unnecessary polling
# input("Press Enter after signing in from another device to proceed, CTRL+C to abort.")

Затем вы передаёте объект словаря потока в метод acquire_token_by_device_flow, чтобы получить токен. По умолчанию этот метод блокирует текущий поток. Вы можете следовать этим инструкциям , чтобы сократить время блокировки или вы можете даже отключить поведение блокировки, а затем продолжить вызов acquire_token_by_device_flow в собственном настраиваемом цикле.

result = app.acquire_token_by_device_flow(flow)

if "access_token" in result:
    access_token = result["access_token"]
else:
    print(result.get("error"))  

Успешный ответ представляет собой словарь с ключом access_token.

Интерактивное получение токена

MSAL Python также предоставляет общедоступным клиентским приложениям (настольным и мобильным) возможность получать токены от имени пользователя. Пользователь входит через URL-адрес запроса авторизации через веб-браузер. Установите URI перенаправления для своего приложения как http://localhost в центре администрирования Microsoft Entra в разделе регистрации приложения. Если при создании PublicClientApplication вы включаете использование брокера, приложению также необходимо зарегистрировать ms-appx-web://Microsoft.AAD.BrokerPlugin/YOUR_CLIENT_ID в качестве URI перенаправления.

result = app.acquire_token_interactive(  # It automatically provides PKCE protection
    scopes=config["scope"])

if "access_token" in result:
    access_token = result["access_token"]
else:
    print(result.get("error"))  

Имя пользователя и пароль

Предупреждение

Этот API не рекомендуется использовать для общедоступных потоков клиентов из-за рисков безопасности, используйте более безопасный поток. Следуйте этому руководству по миграции.

Мы не рекомендуем использовать этот подход. Кроме того, можно получить маркер с именем пользователя и паролем. MSAL Python предусматривает метод acquire_token_by_username_password для этого сценария использования. Не рекомендуется, так как приложение будет запрашивать у пользователя пароль напрямую, что является небезопасным шаблоном.

Существуют более безопасные потоки, которые можно использовать. Дополнительные сведения см. в руководстве по потоку проверки подлинности имени пользователя и пароля .

result = app.acquire_token_by_username_password(
    username=config["username"], password=config["password"], scopes=config["scope"])

if "access_token" in result:
    access_token = result["access_token"]
else:
    print(result.get("error"))  

Интерактивное получение токена конфиденциальным клиентом

Конфиденциальные клиентские приложения могут безопасно хранить секрет и выполнять проверку подлинности от имени приложения, а также от имени данного пользователя. MSAL Python предоставляет разработчикам различные методы получения токенов при разработке ConfidentialClientApplication.

Получить токен для клиента

Получите токен от имени самого приложения с помощью учетных данных клиента, а не от имени пользователя. Например, это можно использовать в приложениях, обрабатывающих пользователей в пакетах, а не в одном конкретном пользователе, например средства синхронизации. MSAL Python предоставляет метод acquire_token_for_client для этого. Начиная с версии 1.23 библиотеки MSAL Python этот метод автоматически пытается получить токен из кэша и отправляет запрос поставщику удостоверений только если в кэше токен не найден.

result = app.acquire_token_for_client(scopes=config["scope"])

if "access_token" in result:
    access_token = result["access_token"]
else:
    print(result.get("error"))    

Получить токен от имени

В случае веб-приложений или веб-API, которые вызывают другой нижестоящий веб-API от имени пользователя, используйте поток On-Behalf-Of, чтобы получить токен на основе утверждения пользователя. Например, SAML и JWT. Текущее приложение — это сервис промежуточного уровня, вызванный с использованием токена, представляющего конечного пользователя. Текущее приложение может использовать такой маркер, также известный как утверждение пользователя, чтобы запросить другой маркер для доступа к нижестоящему веб-API от имени этого пользователя. Приложение среднего уровня не имеет взаимодействия с пользователем для получения согласия. Сведения о получении согласия для вашего приложения среднего уровня см. в документации.

Ниже приведен пример кода, который получает маркер доступа с помощью acquire_token_on_behalf_of метода.

def get(self, request): # a web service endpoint receiving a request
    
    scopes = ["your-scopes"]
    downstream_api = "https://your-downstreamapi.com/resource" #your downstream API resource endpoint
    current_access_token = request.headers.get("Authorization", None)
    
    # initialize the app
    app = msal.ConfidentialClientApplication(...) # refer to initialization of the app documentation

    #acquire token on behalf of the user that called this API
    downstream_api_access_token = app.acquire_token_on_behalf_of(
        user_assertion=current_app_access_token.split(' ')[1],
        scopes=_scopes
    )

    if "access_token" in result:
        access_token = result["access_token"]
        # use access_token to call dowstream API e.g
        requests.get(downstream_api, headers={'Authorization': f'Bearer {downstream_api_access_token}'})
    else:
        print(result.get("error")) 

Получение токена с использованием потока кода авторизации

Для веб-приложений, выполняющих проверку подлинности от имени пользователя, получайте токены через код авторизации после того, как пользователь выполнит вход с помощью URL-адреса запроса авторизации. Обычно это механизм, используемый приложением, которое позволяет пользователю входить и получать доступ к веб-API для конкретного пользователя.

Сначала необходимо инициировать поток кода проверки подлинности с помощью .initiate_auth_code_flow Этот метод принимает среди других параметров URI перенаправления и строку состояния. Значение параметра state также включено в ответ на запрос токена. Если это значение отсутствует, MSAL Python автоматически создаст его самостоятельно. Предоставленный URI перенаправления должен соответствовать URI перенаправления, зарегистрированным в Центр администрирования Microsoft Entra. Этот метод возвращает поток кода проверки подлинности, который является словарем, содержащим auth_uri и state. Это auth_uri URL-адрес, который пользователь должен посетить для входа.

flow = app.initiate_auth_code_flow(
    scopes=config["scope"], redirect_uri=config["redirect_uri"], state="your-state-value")

if "error" in flow:
    print(flow.get("error"))

# Save the response somewhere e.g in session
session["auth_flow"] = flow

# At this point, the app should guide the user to visit the auth ur (session["auth_flow"]["auth_uri"])

Ответ, полученный при обращении к конечным точкам URI аутентификации, используется в методе acquire_token_by_auth_code_flow. Состояние — это уникальный идентификатор, который можно использовать для проверки ответа с сервера авторизации. Пользователь должен дать согласие на области доступа при входе в систему.

# The uth_response value from visiting the auth_uri endpoint is passed as a query string
# You can change this by passing a value to the response_mode in the initiate_auth_code_flow method
try:
    result = app.acquire_token_by_auth_code_flow(session.get("flow", {}), auth_response)
    
    if "access_token" in result:
        access_token = result["access_token"]
    else:
        print(result.get("error"))
except ValueError:  # Usually caused by CSRF
    pass  # Simply ignore them

Кэширование токенов в MSAL Python

Как общедоступные, так и конфиденциальные клиентские приложения поддерживают кэширование токенов, которое напрямую обрабатывается MSAL Python. Приложения должны сначала попытаться получить маркер из кэша, прежде чем полагаться на любые другие средства. Дополнительные сведения см. в рекомендуемой схеме получения токенов.

Чтобы сохранить кэш, разработчикам необходимо настроить логику сериализации кэша маркеров .