Cisco WebEx:使用 Python 2.7 为一组新令牌生成新代码时出现问题

Cisco WebEx: Problem generating a new code for a new set of tokens using Python 2.7

问题在底部。

说明: 我们正在尝试自动化 Cisco WebEx API 的不同方面。例如,从 API 获取所有设备和设备数据,然后呈现它。这些设备可以显示连接状态、位置等等。这只是一个例子。

为了访问 WebEx API,您需要执行以下操作:

  1. 登录您的企业帐户 (https://developer.webex.com)。 然后输入您的密码: 在此之后,所有登录都通过以下方式重定向:

登录后,您可以使用文档并浏览 API 参考。在这里您还可以尝试所有功能,这是使用个人令牌,据我所知,该令牌无法导出或在网站的任何地方看到。您可以复制并使用它,但它会在 24 小时后过期。我想也许您可以使用 Python 登录您的帐户并不断刷新您的个人令牌,但这似乎不是一个好的解决方案。 因此,这让我想到:

  1. 创建一个集成,最终将为您提供 API 访问所需的令牌。 因此,在这里我将展示如何创建集成,从而获得 API 访问所需的代码和令牌。 创建一个新的应用程序,然后 select 集成。 填写所有信息,然后单击添加集成。

  2. 通过接受条款和条件生成用于请求令牌的代码。 添加后,您将被带到应用程序集成页面,在这里您可以看到生成代码所需的所有信息,这些代码将用于生成令牌集。 正如您在黑框中看到的,这是 URL 您需要 copy/paste 进入浏览器然后接受条款和条件,然后才能生成代码。这是结果: 复选框说:“仅在请求新权限时询问” 单击接受后,您将被重定向到创建应用程序集成时指定的 URL。该网站不存在,但仍会显示URL中的代码: 复制代码,您现在可以使用以下代码和应用程​​序中的信息生成令牌集:

代码:

import requests, json

clientID = "C7aa20b0a57cae4127d1e08b15e3a94efacd5c7bb3e1a70ceed4308903a5b807b"
secretID = "b52db3ec6ad8622d0e0e01a0572bac982b214076308ea2e73a566fcf848c9369"
redirectURI = "https://www.your-oauth-website-here.dk/oauth"

def get_tokens(code):
    """Gets access token and refresh token"""
    print("code:", code)
    url = "https://api.ciscospark.com/v1/access_token"
    headers = {'accept':'application/json','content-type':'application/x-www-form-urlencoded'}
    payload = ("grant_type=authorization_code&client_id={0}&client_secret={1}&"
                    "code={2}&redirect_uri={3}").format(clientID, secretID, code, redirectURI)
    req = requests.post(url=url, data=payload, headers=headers)
    results = json.loads(req.text)
    print(results)
    access_token = results["access_token"]
    refresh_token = results["refresh_token"]
    return access_token, refresh_token

test = get_tokens("MWU4YTJmYTgtNjllMy00YjAzLTg0NTQtMTRkYTRiMmIxMzZkNWEzNzRkZDQtYTNk_PF84_33672567-1029-48fb-ba77-7fe2001ee897") # CODE

结果:

code: MWU4YTJmYTgtNjllMy00YjAzLTg0NTQtMTRkYTRiMmIxMzZkNWEzNzRkZDQtYTNk_PF84_33672567-1029-48fb-ba77-7fe2001ee897
{'access_token': 'OTU5MWNhYTItOWNiZC00MWU1LThlZDktNjRlYjI5OGIyYjNmNjI2M2U2MzgtNjAz_PF84_33672567-1029-48fb-ba77-7fe2001ee897', 'expires_in': 1209599, 'refresh_token': 'MGQ4MWRmMzAtYjQyNi00Mzk1LWI0MzAtMmRkMGIzMWQ3ZDVjNzQwZDM3N2YtMWIw_PF84_33672567-1029-48fb-ba77-7fe2001ee897', 'refresh_token_expires_in': 7775999}

如果您尝试使用相同的代码生成新的令牌对,则会显示以下错误:

{'message': "POST failed: HTTP/1.1 400 Bad Request (url = https://idbroker.webex.com/idb/oauth2/v1/access_token, request/response TrackingId = ROUTER_5FD9B9DA-FCB3-01BB-03C9-503F01C403C9, error = '(invalid_grant) Authorization code has been used.')", 'errors': [{'description': "POST failed: HTTP/1.1 400 Bad Request (url = https://idbroker.webex.com/idb/oauth2/v1/access_token, request/response TrackingId = ROUTER_5FD9B9DA-FCB3-01BB-03C9-503F01C403C9, error = '(invalid_grant) Authorization code has been used.')"}], 'trackingId': 'ROUTER_5FD9B9DA-FCB3-01BB-03C9-503F01C403C9'}
Traceback (most recent call last):
  File "c:/Python/test_shit.py", line 117, in <module>
    test = get_tokens("MWU4YTJmYTgtNjllMy00YjAzLTg0NTQtMTRkYTRiMmIxMzZkNWEzNzRkZDQtYTNk_PF84_33672567-1029-48fb-ba77-7fe2001ee897") # CODE
  File "c:/Python/test_shit.py", line 113, in get_tokens
    access_token = results["access_token"]
KeyError: 'access_token'

问题: 令牌有效期设置如下:

在此期间之后,您将必须完成创建新代码的过程,然后请求一组新的令牌。

我正在努力了解如何在 Red Hat Linux 系统上仅使用 Python 2.7.5 和 CLI 界面来自动化获取新代码的过程。

我试过使用请求库打开并点击接受,但没有成功。

这是我尝试通过请求会话在黑匣子中打开代码 URL 时发生的情况的示例:

>>> url = "https://webexapis.com/v1/authorize?client_id=C7aa20b0a57cae4127d1e08b15e3a94efacd5c7bb3e1a70ceed4308903a5b807b&response_type=code&redirect_uri=https%3A%2F%2Fwww.your-oauth-website-here.dk%2Foauth&scope=spark%3Aall%20spark%3Akms&state=set_state_here"
>>> with requests.Session() as s:
...     response = s.get(url)
...
>>> print(response.text)
<!DOCTYPE html>
<html>
<head>
        <meta charset="utf-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<title>
        Sign In - Webex
</title>
<script src="https://code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>
<script>
    window.jQuery || document.write("<script src='/idb/js/jquery-3.5.1.min.js'><\/script>");
</script>
<link rel="stylesheet" href="/idb/css/momentum-ui_fbdee616043ab213856f370993c83f01.min.css"/>
<link rel="stylesheet" href="/idb/css/idbstyle_service_default.css" type="text/css" />
<script src="/idb/js/auth_symphony_997017a549f50f21347311e1488607ab.js"></script>
        <link rel="stylesheet" href="/idb/css/idbstyle_symphony_a2736f93e46b8c14f389ccac12436dcb.css" type="text/css" />

<link rel="apple-touch-icon" sizes="180x180" href="/idb/favicons/apple-touch-icon.png" />
<link rel="icon" type="image/png" sizes="32x32" href="/idb/favicons/favicon-32x32.png" />
<link rel="icon" type="image/png" sizes="16x16" href="/idb/favicons/favicon-16x16.png" />
<link rel="manifest" href="/idb/favicons/manifest.json" />
<link rel="mask-icon" href="/idb/favicons/safari-pinned-tab.svg" color="#07C1E4" />
<link rel="shortcut icon" href="/idb/favicons/favicon.ico" />
<meta name="msapplication-config" content="/idb/favicons/browserconfig.xml" />
<meta name="theme-color" content="#ffffff" />
<meta name="robots" content="noindex, nofollow" />
        <!-- Ref: http://seclab.stanford.edu/websec/framebusting/framebust.pdf -->
<style id="antiClickjack">body{display:none !important;}</style>
<noscript><style>body{display:block !important;}</style></noscript>
<script type="text/javascript">
    if (self === top) {
        var antiClickjack = document.getElementById("antiClickjack");
        antiClickjack.parentNode.removeChild(antiClickjack);
    } else {
        top.location = self.location;
    }
</script>
<script>
        var nameValidated = false;
        var redirectUrl = "https://idbroker.webex.com/idb/IdBGlobalLogin?type=login&goto=https%3A%2F%2Fidbroker.webex.com%2Fidb%2Foauth2%2Fv1%2Fauthorize%3Fclient_id%3DC7aa20b0a57cae4127d1e08b15e3a94efacd5c7bb3e1a70ceed4308903a5b807b%26response_type%3Dcode%26redirect_uri%3Dhttps%253A%252F%252Fwww.your-oauth-website-here.dk%252Foauth%26scope%3Dspark%253Aall%2520spark%253Akms%26state%3Dset_state_here";
        $(document).ready(function() {
                $("#md-form").submit(function(e){
                        e.preventDefault();
                        if(nameValidated) {
                                processForm();
                        }
                });
                var cookieEmail = "";
                if(cookieEmail.length > 0) {
                        $('#GlobalEmailLookupForm').find('input[id="email"]').val(cookieEmail);
                        $('#GlobalEmailLookupForm').find('input[id="isCookie"]').val("true");
                        $('#GlobalEmailLookupForm').submit();
                }
        });
        function validateName(name, nameId) {
        nameId = nameId.replace('IDToken' ,'');
        var divId = 'DivToken' + nameId;
        if(name.length > 0) {
                $.ajax({
                        type: "POST",
                        url: "/idb/validateEmail",
                        data: { user: name, action: 'login', validate: "true" }
                })
                .done(function( responseData ) {
                        if(responseData.status == 'invalid') {
                                document.getElementById('nameContextualError'+nameId).innerHTML = "Enter a valid email address. Example: name@email.com"
                                highlightErrorInputTextbox(divId);
                        } else {
                                nameValidated = true;
                        }
                });
        }
    }
        function processForm() {
                var email = $.trim(document.getElementById('IDToken1').value);
                if(nameValidated) {
                        $('#GlobalEmailLookupForm').find('input[id="email"]').val(email);
                        $('#GlobalEmailLookupForm').submit();
                } else {
                        if(email.length > 0) {
                        $.ajax({
                                type: "POST",
                                url: "/idb/validateEmail",
                                data: { user: email, action: 'login', validate: "true" }
                        })
                        .done(function( responseData ) {
                                if(responseData.status == 'invalid') {
                                        document.getElementById('nameContextualError1').innerHTML = "Enter a valid email address. Example: name@email.com"
                                        highlightErrorInputTextbox('DivToken1');
                                } else {
                                        $('#GlobalEmailLookupForm').find('input[id="email"]').val(email);
                                        $('#GlobalEmailLookupForm').submit();
                                }
                        });
                }
                }
                return false;
        }
</script>
        <style>
                @media (forced-colors: active) {
                        .md-button--blue {
                                border: 1px solid;
                        }
                }
        </style>
</head>
<body id="login" class="md md--sites">
        <div id="globalInfo" style="display:none;">
                <div>
                        It appears that cookies are not enabled on your computer, so some functions will not work. To enable cookies, change the privacy settings in your browser, and then refresh the page.
                </div>
                <a id="close_crossplatform_message" href="javascript:">
                        Close
                </a>
        </div>
        <noscript>
                <div>
                        It appears that JavaScript is not enabled on your computer, so some functions will not work. To enable JavaScript, change the privacy settings in your browser, and then refresh the page.
                </div>
        </noscript>
        <div class="md-panel md-panel--form md-panel--full">
                <div class="md-panel__main">
            <div class="md-panel__image ci__logo"></div>
                        <div class="md-panel__title">
                Enter your email address
            </div>
                        <form class="md-panel__form" id="md-form" novalidate="">
                <div class="md-input-container md-input--filled" id="DivToken1">
                                        <div class="md-input__wrapper">
                                                <input class="md-input" id="IDToken1" data-monitor-id="IDToken1"
                                                        name="IDToken1" value="" autocomplete="email"
                                                        placeholder="Email address"
                                                        alt="Email address"
                                                        onblur="validateName($.trim(this.value), this.id);" maxlength="512"
                                                        type="email" autofocus>
                                        </div>
                    <div class="md-input__messages" id="DivErrorToken1">
                        <div class="message" id="nameContextualError1">
                            Enter the email address for your Webex account.
                        </div>
                    </div>
                </div>
                <div class="md-panel__cta">
                    <button name="btnOK" type="submit" id="IDButton2"
                            class="md-button md-button--blue" onClick="processForm();">
                        Next
                    </button>
                </div>
                        </form>
                </div>
                <form name="GlobalEmailLookup" id="GlobalEmailLookupForm" method="post" action="/idb/globalLogin">
                        <input type="hidden" id="email" name="email" value="" />
                        <input type="hidden" id="isCookie" name="isCookie" value="false" />
                        <input type="hidden" id="ForceAuth" name="ForceAuth" value="false" />
                        <input type="hidden" id="cisService" name="cisService" value="common" />
                                <input type="hidden" name="gotoUrl" value="aHR0cHM6Ly9pZGJyb2tlci53ZWJleC5jb20vaWRiL29hdXRoMi92MS9hdXRob3JpemU/Y2xpZW50X2lkPUM3YWEyMGIwYTU3Y2FlNDEyN2QxZTA4YjE1ZTNhOTRlZmFjZDVjN2JiM2UxYTcwY2VlZDQzMDg5MDNhNWI4MDdiJnJlc3BvbnNlX3R5cGU9Y29kZSZyZWRpcmVjdF91cmk9aHR0cHMlM0ElMkYlMkZ3d3cueW91ci1vYXV0aC13ZWJzaXRlLWhlcmUuZGslMkZvYXV0aCZzY29wZT1zcGFyayUzQWFsbCUyMHNwYXJrJTNBa21zJnN0YXRlPXNldF9zdGF0ZV9oZXJl" />
                        <input type="hidden" id="encodedParamsString" name="encodedParamsString" value="dHlwZT1sb2dpbiY=" />
                </form>
<div id="footer" class="md-panel__footer">
    <img class="footer__logo" src="/idb/images/cisco-webex/lockup/cisco-webex-lockup-blue.svg" alt="Cisco Webex logo"/>
    <div id="footer-links" class="footer__copyright">
        By using Webex you accept the
            <a href="https://www.cisco.com/c/en/us/about/legal/cloud-and-software/cloud-terms.html" target="_blank" rel="noopener">
                Terms of Service
            </a> &
            <a href="https://www.cisco.com/web/siteassets/legal/privacy.html" target="_blank" rel="noopener">
                Privacy Statement
            </a>.
            <a href="https://www.webex.com" target="_blank" rel="noopener">
                Learn more about
            </a> Webex
    </div>
</div>
        </div>
</body>
</html>

我刚看到登录屏幕。

或者:有没有办法使用 Python CLI 登录 WebEx 网站?

如果我可以登录到 Cisco WebEx 开发人员站点,然后使用此会话获取新代码,那可能会成功。

更新: 我已经设法通过了“输入电子邮件地址”,但我现在一直停留在输入密码,但我继续研究如何登录 WebEx 网站。

with requests.Session() as s:
    login_url = "https://developer.webex.com/login"
    result = s.get(login_url)
    payload = { "email": "xx@xx.xx" }
    print(result.url)
    result = s.post(result.url, data=payload)
    print(result.text)

如有任何想法,我们将不胜感激。

谢谢。

原来我没有正确阅读文档,对花费时间的人表示歉意reading/etc。

当刷新普通令牌时,刷新令牌过期也会重置。我不知道是这种情况,但在今天联系 Cisco Dev 支持后,他们向我展示了。

官方回复是:

Hi XXX,

Thank you for contacting Webex Developer Support. There is no way to fully automate the OAuth Grant Flow, as the first manual step, where the user authorises the integration to act on their behalf is always mandatory. However once the access token expires or even before that, you can use the refresh token to extend the validity of the access token. With that, the validity of the refresh token will also be renewed, so you can practically keep refreshing your access token indefinitely. The refresh token expiry time is reset at most once a day for performance reason, so the counter will seem to be counting down within the span of one day, but if you were to refresh it the following day, you should see that time/integer go back up.

我用来刷新令牌的代码:

def refreshCiscoWebExToken(refresh_token):
    """Refresh access token"""
    payload = ( "grant_type=refresh_token&client_id={0}&client_secret={1}&"
                "refresh_token={2}").format(clientID, secretID, refresh_token)
    response = requests.post(url=TokenUrl, data=payload, headers=TokenHeaders)
    if response.status_code == 200:
        results = json.loads(response.text)
        access_token = results["access_token"]
        expires_in = results["expires_in"]
        return(access_token, expires_in)

我希望这 can/will 能帮助其他人寻找答案。