【问题标题】:Microsoft Graph API delegated permissionMicrosoft Graph API 委派权限
【发布时间】:2017-08-03 18:08:49
【问题描述】:

我想代表用户使用 Graph API 授权我的应用程序(python 脚本)。我使用this document 作为参考。

关注: 我想用python来做。我是否可以使用请求模块并请求授权码。这将自动打开浏览器,将要求用户输入凭据,一旦他/她通过身份验证,脚本将自动接收授权码。然后我将使用脚本中的授权码来获取访问令牌。

谢谢。

【问题讨论】:

    标签: python python-3.x python-requests microsoft-graph-api azure-ad-graph-api


    【解决方案1】:

    是的,这是绝对可能的。我在GitHub sample here 中执行这些步骤。

    一些相关的代码片段:

    身份验证.py

    # External Python Libraries Used:
    import requests
    
    # Our Python Functions:
    import appconfig as g
    
    # Create headers for REST queries. Used for both ARM and AAD Graph API queries.
    def create_headers(access_token):
        return {
            'Authorization': 'Bearer ' + access_token,
            'Accept': 'application/json',
            'Content-Type': 'application/json'
            }
    
    ### Start of Authorization Code Grant Flow Authentication
    # Note for the Authorization Code Grant Flow, we use the 'common' endpoint by default, rather than specifying a tenant.
    
    # Generate AAD Login URL
    def login_url(state, redirect_uri, tenant_id='common'):
        params = {
            'url': g.aad_endpoint + tenant_id + '/oauth2/authorize',
            'response_type': 'code',
            'client_id': g.clientId,
            'redirect_uri': redirect_uri,
            'state': state
            }
    
        # You can add additional querystrings here if you want to do things like force login or prompt for consent
        login_url = '%(url)s?response_type=%(response_type)s&client_id=%(client_id)s&redirect_uri=%(redirect_uri)s&state=%(state)s' %params
    
        # Return URL
        return login_url
    
    # Get Access Token using Authorization Code
    def get_access_token_code(code, redirect_uri, resource, tenant_id='common'):
        payload = {
            'client_id': g.clientId,
            'code': code,
            'grant_type': 'authorization_code',
            'redirect_uri': redirect_uri,
            'resource': resource,
            'client_secret': g.clientSecret
        }
    
        token_endpoint = g.aad_endpoint + tenant_id + '/oauth2/token'
        r = requests.post(token_endpoint, data=payload)
    
        # Return raw Access Token
        return r.json()['access_token']
    
    ### End of Authorization Code Grant Flow Authentication
    
    ### Start of Client Credential Flow Authentication
    # Note that we need to specify Tenant ID for these App Only Tokens. If you use the 'common' endpoint, it will choose the tenant where the app is registered.
    def get_access_token_app(resource, tenant_id):
        payload = {
            'client_id': g.clientId,
            'grant_type': 'client_credentials',
            'resource': resource,
            'client_secret': g.clientSecret
            }
    
        token_endpoint = g.aad_endpoint + tenant_id + '/oauth2/token'
        r = requests.post(token_endpoint, data=payload)
    
        # Return raw Access Token
        return r.json()['access_token']
    

    views.py

    # Login Page for both Customer and Partner
    @app.route('/<string:user_type>/login', methods = ['POST', 'GET'])
    def login(user_type):
        # Check if there is already a token in the session
        if ('access_token_arm' in session) and ('access_token_graph' in session):
            return redirect(url_for(user_type))
    
        # Use State Parameter to help mitigate XSRF attacks
        guid = uuid.uuid4()
        session['state'] = guid
    
        # Need to send the full Redirect URI, so we use _external to add root domain
        redirect_uri = login_url(session['state'], url_for('authorized', user_type=user_type, _external=True))
    
        return redirect(redirect_uri, code=301)
    
    # Logout page which scrubs all the session data.
    @app.route('/logout', methods = ['POST', 'GET'])
    def logout():
        session.clear()
        return redirect(url_for('index'))
    
    # Recieve the Authorization Code, and exchange it for Access Tokens to both ARM and AAD Graph API
    @app.route('/<string:user_type>/login/authorized')
    def authorized(user_type):
        #Capture code in the URL
        code = request.args['code']
    
        # Check that the state variable was not touched
        if str(session['state']) != str(request.args['state']):
            raise Exception('State has been messed with, end authentication')
    
        redirect_uri = url_for('authorized', user_type=user_type, _external=True)
        session['access_token_arm'] = get_access_token_code(code, redirect_uri, g.resource_arm)
        session['access_token_graph'] = get_access_token_code(code, redirect_uri, g.resource_graph)
    
        # Return user to their appropriate landing page
        return redirect(url_for(user_type))
    

    graph.py

    # Get tenant details for the signed in user. We only return Tenant Display Name and Tenant ID, but more information can be accessed if necessary.
    def get_tenant_details(access_token):
        headers = create_headers(access_token)
    
        params = {
            'url': g.resource_graph,
            'api_version': g.api_version_graph
            }
    
        # Note we are using the "myorganization" endpoint, which figures out tenant information from the claims in the access token
        tenant_details_url = '%(url)s/myorganization/tenantDetails?api-version=%(api_version)s' %params
        r = requests.get(tenant_details_url, headers=headers)
    
        #Return Tenant Display Name String and Tenant ID GUID
        return r.json()['value'][0]['displayName'], r.json()['value'][0]['objectId']
    
    # Get user details for the signed in user. We only return the User Principal Name (username) of the user, but more information can be accessed if necessary.
    def get_user_details(access_token):
        headers = create_headers(access_token)
    
        params = {
            'url': g.resource_graph,
            'api_version': g.api_version_graph
            }
    
        # Note we are using the "me" endpoint, which figures out tenant and user information from the claims in the access token
        user_details_url = '%(url)s/me?api-version=%(api_version)s' %params
        r = requests.get(user_details_url, headers=headers)
    
        # Return Username String for user.
        return r.json()['userPrincipalName']
    

    【讨论】:

    • 那么当你请求授权码时,它会打开一个浏览器并要求用户登录?并且一旦用户登录,验证码将被脚本捕获,然后它会请求访问令牌?
    • 是的,我使用 def login_url(state, redirect_uri, tenant_id='common') 函数生成登录 URL 并将用户重定向到此页面。
    • 肖恩,我正在尝试你的代码。但是,我收到授权码后出现错误。 Key_error:access_token。文件“C:\Downloads\Azure-Service-Health-Partner-Monitor-REST-API\Azure-Service-Health-Partner-Monitor-REST-API\views.py”,第 54 行,在授权会话中 ['access_token_arm' ] = get_access_token_code(code, redirect_uri, g.resource_arm) 文件“C:\Downloads\Azure-Service-Health-Partner-Monitor-REST-API\Azure-Service-Health-Partner-Monitor-REST-API\authentication.py ",第 49 行,在 get_access_token_code 中返回 r.json()['access_token']
    • 我的示例尝试获取对两种不同资源的访问令牌:Azure 资源管理器和 AAD Graph API。如果您的应用没有为此配置,您可能希望删除与 Azure 资源管理器相关的内容。
    • 您需要或分享错误详情...也许打开一个新的堆栈溢出帖子进行调试
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-04-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-28
    • 1970-01-01
    相关资源
    最近更新 更多