401 Несанкционированная ошибка.Не удалось обновить код авторизации в объект учетных данных

#android #python-3.x #flask #oauth-2.0 #google-oauth

#Android #python-3.x #flask #oauth-2.0 #google-oauth

Вопрос:

Я использую oauth 2.0 с гибридным потоком для входа в Google https://developers.google.com/identity/sign-in/web/server-side-flow в моем приложении для Android. Я получаю одноразовый код авторизации в приложении Android и отправляю его в свой flask api через postman. Когда я применяю flow.step2_exchange к этому одноразовому коду аутентификации в api, он выдает ошибку обмена потоками. Я проверил, что код аутентификации, который поступает в API, такой же, как и в моем приложении. Я не могу найти причину ошибки.

Мой одноразовый код аутентификации выглядит следующим образом: 4 /qXilPdy7xOVe5swCBlVRrxjuVu8zEzfcmidlooo7_ls

Фрагмент кода моего api flask:

 # IMPORTS FOR THIS STEP
from oauth2client.client import flow_from_clientsecrets
from oauth2client.client import FlowExchangeError
import httplib2
import json
from flask import make_response
import requests


app = Flask(__name__)

CLIENT_ID = json.loads(
    open('client_secrets.json', 'r').read())['web']['client_id']
APPLICATION_NAME = "OAUTH_SERVER"
SCOPES = [
    'https://www.googleapis.com/auth/gmail.readonly',
    'https://www.googleapis.com/auth/userinfo.email',
    'https://www.googleapis.com/auth/userinfo.profile',
    # Add other requested scopes.
]

# Connect to Database and create database session
engine = create_engine('sqlite:///restaurantmenu.db')
Base.metadata.bind = engine

DBSession = sessionmaker(bind=engine)
session = DBSession()

@app.route('/gconnect', methods=['POST'])
def gconnect():
    request.get_data()
    code = request.data.decode('utf-8')
    print (code)

    # Upgrade the authorization code into a credentials object
    oauth_flow = flow_from_clientsecrets('client_secrets.json', scope = SCOPES)
    oauth_flow.redirect_uri = 'postmessage'
    try:
        credentials = oauth_flow.step2_exchange(code)
        if credentials is None:
            print ("it is empty")
    except FlowExchangeError:
        response = make_response(
            json.dumps('Failed to upgrade the authorization code.'), 401)
        response.headers['Content-Type'] = 'application/json'
        return response
 

Мой client_secret.json для Api называется OAUTH_SERVER и выглядит следующим образом:

 {"web":
      {"client_id":"matches the one in console.apps.googleusercontent.com",
"project_id":"oauthapi",
"auth_uri":"https://accounts.google.com/o/oauth2/auth",
"token_uri":"https://accounts.google.com/o/oauth2/token",
"auth_provider_x509_cert_url":"https://www.googleapis.com/oauth2/v1/certs",
"client_secret":"###########",
"redirect_uris["http://localhost:5000/gconnect","http://localhost:5000/"],
"javascript_origins":["http://localhost:5000"]}
}
 

Ответ №1:

Как я вижу, это из курса Udacity — Аутентификация и авторизация. Пожалуйста, проверьте, не login.html содержит правильное значение data-clientid. У меня была такая же проблема, потому что при копировании забыл изменить ее на мою.

Комментарии:

1. Вы правы, это из курса Udacity, но я адаптировал этот код для своего проекта Android. Поэтому у меня нет login.html . Я успешно вхожу в систему через свое приложение для Android, затем получаю одноразовый код аутентификации и отправляю его в api. Мое приложение и api имеют разные client_secrets (предполагается, что в случае app api). client_secret.json в моем API имеет веб-тип (api). Я проверил значение идентификатора клиента. Я также публикую формат моего client_secret JSON в моем вопросе, на случай, если с ним что-то не так.

2. Итак, чтобы убедиться, что у вас есть приложение для Android, которое является серверной частью клиента и сервера Flask (API). Почему они проходят проверку подлинности отдельно в Google? Я думаю, что мобильное приложение является клиентом, который должен обернуть логику в «login.html » и ваш серверный сервер должен иметь client_secret . Мобильное приложение не должно иметь client_secret.

3. В курсе udacity использовался один идентификатор клиента, секрет клиента, но я не могу этого сделать в моем случае, потому что веб-приложение и приложение Android имеют разные google_services json, которые нельзя обменять. А также для получения одноразового кода авторизации в приложении Android я должен предоставить идентификатор клиента внутреннего сервера в приложении. Проверьте эту ссылку developers.google.com/identity/sign-in/android/backend-auth .

4. Это ссылка из документов Google : developers.google.com/identity/sign-in/android/start

Ответ №2:

Я думаю, вам нужно изменить

# Upgrade the authorization code into a credentials object
oauth_flow = flow_from_clientsecrets('client_secrets.json', scope = SCOPES)
oauth_flow.redirect_uri = 'postmessage'
try:
credentials = oauth_flow.step2_exchange(code)
if credentials is None:
print ("it is empty")
except FlowExchangeError:

Для

try:
# Upgrade the authorization code into a credentials object
oauth_flow = flow_from_clientsecrets('client_secrets.json', scope='')
oauth_flow.redirect_uri = 'postmessage'
credentials = oauth_flow.step2_exchange(code)
except FlowExchangeError:

Комментарии:

1. Он по-прежнему выдает ту же ошибку. Я взял первые две строки из «попытки», чтобы найти строку кода, выдающую ошибку.