如何让 selenium 从 Web 应用程序获取 oauth 访问令牌?

问题描述 投票:0回答:1

这完全令人抓狂...我有 OAuth2.0 请求发送到 web 应用程序,并且我想使用 python selenium 检索我的访问令牌。

我尝试使用 rauthrequestsoauthlib.oath2生成我的 api 密钥后获取访问令牌。 Selenium 是我看到任何结果的唯一途径,所以我可能会完全错过目标。

唯一的亮点就是这个......

  1. 我看不到浏览器句柄。
  2. 我不知道任何 xpath 元素。
  3. 我在 Chrome 开发者工具的弹出窗口中看不到任何 HTML。

Datto API 文档 表示使用 Postman 来获取您的访问令牌令牌。我可以从 python 中执行 API 调用,但这不是一个非常可重复的过程。

Datto 的所有示例也采用了此流程。

如何使用 selenium 或 python 脚本来简单地执行 oauth 检索我的访问令牌,以便我可以在将来的请求中对其进行变量化?

from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.common.by import By
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.alert import Alert
import time

#Oauth2.0 credentials.
client_id = 'public-client'
client_secret = 'public'

# URLs to retrieve tokens
authorize_url = "https://zinfandel-api.centrastage.net/auth/oauth/authorize"
access_token_url = "https://zinfandel-api.centrastage.net/auth/oauth/token"

# This is your API Public Key.
auth_user = 'YOUR_PUBLIC_KEY_HERE'

# This is your API Secret Key.
auth_pass = 'YOUR_SECRET_KEY_HERE'

# This installs the driver that selenium needs to open your browser.
browser = webdriver.Chrome(service=Service(ChromeDriverManager().install()))

#browser.maximize_window()

time.sleep(3)

# This goes to a website.
browser.get(access_token_url)

# Used to download page source code
with open("page_source.html", "w") as f:
    f.write(browser.page_source)
    f.close()

time.sleep(5)

# A list of all window handles
main_window_handle = browser.window_handles

# Handle of the first window open.
main_window = main_window_handle[0]

# This will switch us to a new window if there is more than one.
# Right now the web app isn't being seen as a window.
for handle in browser.window_handles:
    if handle != main_window:
        popup = handle
        #print(popup)
        browser.switch_to.window(popup)

time.sleep(3)

print("Starting anonymous key send.")

actions = ActionChains(browser)

time.sleep(3)

popup_alert = Alert(browser)

print(popup_alert.page_source)


# This will error out because the page isn't an alert.
#browser.switch_to.alert

# Is this an Alert?
#with open("active_elment_alert.html", "w") as f:
#    f.write(browser.page_source)
#    f.close()

# I'm going to try to switch to a frame and write to it.
browser.switch_to.frame

# If this is a frame we'll see soething here.
with open("active_elment_frame.html", "w") as f:
    f.write(browser.page_source)
    f.close()


browser.switch_to.active_element

# Used to download active element source code.
# You can see that after I switch I don't see any html other than what was presented earlier.
with open("active_elment_source.html", "w") as f:
    f.write(browser.page_source)
    f.close()

################## I THINK THIS IS WHERE I NEED HELP ##################
#This is probably just posting nonsense in the empty html body.

# I'm trying to xpath to either a label or anything with the username field.
mystery_field = browser.find_element(By.XPATH,'//*[contains(text(),ernam)]')
#mystery_field = browser.find_element(By.XPATH,"//label[contains(text(),ernam)]")

print(mystery_field.text)

#start_a_doing_stuff = browser.switch_to.frame(mystery_field)

time.sleep(3)

actions.click(mystery_field).perform

time.sleep(3)

actions.send_keys(client_id).perform()

time.sleep(3)

actions.send_keys(Keys.TAB).perform()

time.sleep(3)

actions.send_keys(client_secret).perform()

time.sleep(3)

actions.send_keys(Keys.RETURN).perform()

time.sleep(3)

print("The anonymous key send is done.")

time.sleep(3)

################## I THINK THIS IS WHERE I NEED HELP ##################

# This portion appropriately sends content to authorize url.

#user_name_field = browser.find_element(By.NAME, "username")
#password_field = browser.find_element(By.NAME, "password")

#user_name_field.send_keys(auth_user)

#user_name_field.send_keys(Keys.TAB)

#password_field.send_keys(auth_pass)

#password_field.send_keys(Keys.RETURN)

#actions.perform()

#time.sleep(3)

#When everything is done, this closes your browser.
browser.quit()

当脚本运行时,您可以在用户名字段中看到光标,当您访问该站点时,html 正文为空。

但是,在无法看到任何字段的情况下,我试图在身份验证警报框打开后立即将密钥发送到光标。

我知道硒不会将其视为警报,因为当我尝试将密钥发送到警报元素时,我的代码出错了。

python-3.x selenium rest oauth-2.0 python-requests
1个回答
0
投票

现代 Web 应用程序中,OAuth 令牌有点难以获取。 用户不会有专用端点来请求 user_credentials 来获得 access_token

其中一种方法是用户需要手动登录Web应用程序,然后需要获取令牌。 这可以在 Web 自动化中借助 Selenium Dev Tools版本 > 4)或借助 浏览器代理工具 来实现。 API自动化用户可以启动Headless Browser来获取令牌。


通过 Selenium DevTools 获取令牌:

需要注意的是,通过第三方工具,用户将只能获取 OAuth 令牌的 OPTIONS 请求(不是响应中包含 access_token 的 POST 请求)。

因此,用户需要查找任何特定的 Web 应用程序 API 请求,该请求将包含 与 AUTHERTICATION = Bearer 相同的 access_token。 查找请求标头。

以下代码片段

{
    writer = new BufferedWriter(new FileWriter("network_logs.txt", false));

    // Add listener for network requests
    devTools.addListener(Network.requestWillBeSent(), request -> {
        // Store the request in the map
        requestMap.put(request.getRequestId().toString(), request);
    });

    // Add listener for network responses
    RequestId[] requestIds = new RequestId[1];
    devTools.addListener(Network.responseReceived(), response -> {
        try {
            requestIds[0] = response.getRequestId();
            String requestId = response.getRequestId().toString();
            Response res = response.getResponse();

            if (requestMap.containsKey(requestId)) {
                RequestWillBeSent req = requestMap.get(requestId);
                String url = res.getUrl();

                // System.out.println(url);
                if (url.contains(<USER_WEBAPPLICATION_REQUEST_URL>) && req.getRequest().getMethod().equalsIgnoreCase("POST")) { // Filter for specific endpoint
                    // Write request details to file
                    writer.write("\n\t\t=========== NEW REQUEST BEGINS ============ \n");
                    writer.write("Request URL: " + req.getRequest().getUrl() + "\n");
                    writer.write("Request Method: " + req.getRequest().getMethod() + "\n");
                    writer.write("Request Headers: " + req.getRequest().getHeaders() + "\n");
                    writer.write(
                            "Request Access Token: " + extractAccessToken(req.getRequest().getHeaders()) + "\n");
                    writer.write("---------------------------------\n");

                    // Write response details to file
                    writer.write("Response URL: " + url + "\n");
                    writer.write("Response Status: " + res.getStatus() + "\n");
                    writer.write("Response Headers: " + res.getHeaders() + "\n");

                    try {
                        GetResponseBodyResponse responseBody = devTools
                                .send(Network.getResponseBody(response.getRequestId()));
                        if (responseBody != null) {
                            String body = responseBody.getBody();
                            writer.write("Response Body: " + body + "\n");
                        } else {
                            writer.write("Response Body: [No Content]\n");
                        }
                    } catch (Exception e) {
                        writer.write("---> Response Body: Failed to get response body: " + e.getMessage() + "\n");
                    }
                    writer.write("\t\t=========== REQUEST ENDS ============\n");
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    });

    // Navigate to a website
    try {
        driver.get(webURL);
    } catch (Exception e) {
        System.out.println(e.getLocalizedMessage());
    }

    loggingMethod(); // POST Logging in, we need to extract token

}

© www.soinside.com 2019 - 2024. All rights reserved.