Q/A - 编辑没有合作伙伴的 Microsoft 订阅的许可证数量 API - 将 ajaxsessionkey 从 selenium 传递到请求模块

Q/A - Edit license amount for Microsoft subscriptions without partner API - Passing ajaxsessionkey from selenium to requests module

我目前使用 selenium 登录 Microsoft 管理中心并增加或减少我选择的 office 订阅;但是我想尝试只使用 python 附带的 http 请求库来发出我的请求。

我为什么要这样做 - 由于特定情况,我无法使用合作伙伴 api 来增加许可。我可以访问我客户的 MS 管理员帐户,并希望在使用 MS 图形创建用户时使用 python 来增加许可证。

我试过的 - 我首先尝试创建 http 请求以登录到 MS....这似乎不可能:Logging into Microsoft Online website programatically with C# & 我试过了,但似乎我需要找到正常使用网页时生成的 xsrf token

所以我决定使用 selenium 登录 MS,然后弄清楚如何在登录 MS 时使用 commerce API

这是我的代码:

from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.actions import action_builder
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.action_chains import ActionChains
from auths.AA_auth import interm_auth, otpauth
from selenium.common import exceptions
import time

import requests
import json
def browser_options():
    options = Options()
    options.headless = True
    options.add_argument('--no-sandbox')
    options.add_argument('--disable-dev-shm-usage')
    browser_options.browser = webdriver.Chrome(options=options)
    return browser_options.browser

def mslogin(msdata):
    #Go to the specific subscription in question
    browser_options.browser.get("https://admin.microsoft.com/Adminportal/Home?#/subscriptions/webdirect/ENTERSKUIDHERE")
    
    #Enter email
    ms_username = browser_options.browser.find_element_by_css_selector('#i0116')
    ms_username.send_keys("ENTERADMINEMAIL")

    wait = WebDriverWait(browser_options.browser, 10)
    wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, '#idSIButton9')))
    ms_usernameaccept = browser_options.browser.find_element_by_css_selector('#idSIButton9')
    ms_usernameaccept.send_keys(Keys.ENTER)

    #Enter password
    wait = WebDriverWait(browser_options.browser, 5)
    wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, '#i0118')))
    ms_password = browser_options.browser.find_element_by_css_selector('#i0118')
    ms_password.send_keys("ENTERADMINPASSWORD")

    wait = WebDriverWait(browser_options.browser, 10)
    wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, '#idSIButton9')))
    ms_passwordaccept = browser_options.browser.find_element_by_css_selector('#idSIButton9')
    ms_passwordaccept.send_keys(Keys.ENTER)

    #Getting past the reduced password inquiry webpage
    wait = WebDriverWait(browser_options.browser, 5)
    wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, '#idBtn_Back')))
    reducedlogingcancel = browser_options.browser.find_element_by_css_selector('#idBtn_Back')
    reducedlogingcancel.send_keys(Keys.ENTER)
    time.sleep(1)

    #Get cookieinfo
    request_cookies_browser =  browser_options.browser.get_cookies()
    browser_options.browser.close()
    print(request_cookies_browser)

    s = requests.Session()
    for cookie in request_cookies_browser:
        s.cookies.set(cookie['name'], cookie['value'])

    X = ENTERNUMBERHERE

    patchheaders = {
                "accept":"application/json, text/plain, */*",
                "content-type": "application/json",
            }
    licenseincrease = {
        "totalLicenses":X
    }
    licenseincrease_json = json.dumps(licenseincrease)
    getlicense = s.patch("https://admin.microsoft.com/fd/commerceapi/my-org/subscriptions/ENTERSKUIDHERE", headers=patchheaders, data=licenseincrease_json)
    getlicense_json = getlicense.json()
    print(getlicense_json)

但是我遇到了一个错误:

{Message: "There was an error processing the request.", StackTrace: "", ExceptionType: ""}

我是否缺少解决此问题的方法?或者有没有更好的方法来使用 commerce API 使用 http 请求?

注意:(这是一个问题和答案的设置。如果您有更好的方法,请在下面留下答案或评论)

要向商业 api 提出补丁请求(登录到 MS 时),您需要将 s.AjaxSessionKey 添加到请求中。添加密钥后,它应该 return 支持订阅 json 数据,您可以在其中查看总许可数量:

patchheaders = {
                "accept":"application/json, text/plain, */*",
                "content-type": "application/json",
                "ajaxsessionkey":s.cookies.get("s.AjaxSessionKey")
            }