【问题标题】:Configuring Auth0 authentication on Google App Engine Standard and the Cloud Endpoints Frameworks with Python使用 Python 在 Google App Engine Standard 和 Cloud Endpoints Frameworks 上配置 Auth0 身份验证
【发布时间】:2018-12-02 14:31:15
【问题描述】:

我在 Google Cloud App Engine 标准环境中使用 Cloud Endpoints Frameworks with Python 来提供 API。

据我所知,我应该能够将 Endpoints Frameworks 中的 python 装饰器与 endpointscfg.py 命令行工具结合使用,以使用 Auth0 自动设置基于令牌的身份验证; endpointscfg.py 命令行会自动创建用于配置 Google Endpoints 代理的 openapi.json 文件。

这是我的装饰器示例,用于回显内容的 API:

# # [START echo_api]
@endpoints.api(
    name='echo',
    version=_VERSION,
    api_key_required=True,
    audiences={'auth0': ['https://echo.<my-project>.appspot.com/_ah/api/echo/v1/echo']},
    issuers={'auth0': endpoints.Issuer(
        'https://<my-project>.auth0.com',
        'https://<my-project>.auth0.com/.well-known/jwks.json')}
)
class EchoApi(remote.Service):
    ...

当我运行 endpointscfg.py 命令行工具时,我在 openapi.json 文件中得到了一些看起来很正确的内容:

"paths": {
    "/echo/v1/echo": {
      "post": {
        "operationId": "EchoApi_echo",
        "parameters": [
          {
            "in": "body",
            "name": "body",
            "schema": {
              "$ref": "#/definitions/MainEchoRequest"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A successful response",
            "schema": {
              "$ref": "#/definitions/MainEchoResponse"
            }
          }
        },
        "security": [
          {
            "api_key": [],
            "auth0_jwt": []
          }
        ]
      }
    }

"securityDefinitions": {
    "api_key": {
      "in": "query",
      "name": "key",
      "type": "apiKey"
    },
    "auth0_jwt": {
      "authorizationUrl": "https://<my-project>.auth0.com/authorize",
      "flow": "implicit",
      "type": "oauth2",
      "x-google-issuer": "https://<my-project>.auth0.com",
      "x-google-jwks_uri": "https://<my-project>.auth0.com/.well-known/jwks.json",
      "x-google-audiences": "https://echo.<my-project>.appspot.com/_ah/api/echo/v1/echo"
    }
  }

因此,问题在于此设置似乎什么都不做,并且如果不存在令牌或令牌无效,则不会检查传入的令牌以防止访问。

我已经能够使用 python-jose 库在 API 回显函数中设置不记名令牌的手动处理(如果做得不好,很抱歉,但我只是在测试,欢迎使用 cmets):

authorization_header = self.request_state.headers.get('authorization')
    if authorization_header is not None:
        if authorization_header.startswith('Bearer '):
            access_token = authorization_header[7:]
            logging.info(access_token)
        else:
            logging.error("Authorization header did not start with 'Bearer '!")
            raise endpoints.UnauthorizedException(
                    "Authentication failed (improperly formatted authorization header).")
        else:
            logging.error("Authorization header did not start with 'Bearer '!")
            raise endpoints.UnauthorizedException("Authentication failed (bearer token not found).")

r = urlfetch.fetch(_JWKS_URL)
jwks_content = json.loads(r.content)
keys = jwks_content['keys']
public_key = jwk.construct(keys[0])
logging.info(public_key)

message, encoded_signature = str(access_token).rsplit('.', 1)
# decode the signature
decoded_signature = base64url_decode(encoded_signature.encode('utf-8'))
# verify the signature
if not public_key.verify(message.encode("utf8"), decoded_signature):
    logging.warning('Signature verification failed')
    raise endpoints.UnauthorizedException("Authentication failed (invalid signature).")
else:
    logging.info('Signature successfully verified')

claims = jwt.get_unverified_claims(access_token)
# additionally we can verify the token expiration
if time.time() > claims['exp']:
    logging.warning('Token is expired')
    raise endpoints.UnauthorizedException("Authentication failed (token expired).")
# and the Audience  (use claims['client_id'] if verifying an access token)
if claims['aud'] != _APP_CLIENT_ID:
    logging.warning('Token was not issued for this audience')
    raise endpoints.UnauthorizedException("Authentication failed (incorrect audience).")
# now we can use the claims
logging.info(claims)

此代码有效,但我认为设置装饰器和配置 openapi.json 文件的全部目的是将这些检查卸载到代理,以便只有有效的令牌才能访问我的代码。

我做错了什么?

更新: 可能我需要在我的代码中检查 endpoints.get_current_user() 来控制访问。但是,我刚刚在我的日志中注意到以下内容:

Cannot decode and verify the auth token. The backend will not be able to retrieve user info (/base/data/home/apps/e~<my-project>/echo:alpha23.414400469228485401/lib/endpoints_management/control/wsgi.py:643)
Traceback (most recent call last):
  File "/base/data/home/apps/e~<my-project>/echo:alpha23.414400469228485401/lib/endpoints_management/control/wsgi.py", line 640, in __call__
    service_name)
  File "/base/data/home/apps/e~<my-project>/echo:alpha23.414400469228485401/lib/endpoints_management/auth/tokens.py", line 75, in authenticate
    error)
UnauthenticatedException: (u'Cannot decode the auth token', UnauthenticatedException(u'Cannot find the `jwks_uri` for issuer https://<my-project>.auth0.com/: either the issuer is unknown or the OpenID discovery failed',))

但是,我认为一切都已配置好。知道为什么尽管 openapi.json 文件中的路径是正确的,但仍然找不到“jwks_uri”吗?

【问题讨论】:

    标签: google-app-engine authentication auth0 openapi google-cloud-endpoints-v2


    【解决方案1】:

    我是这些框架的当前维护者。您确实需要检查endpoints.get_current_user() 来控制访问,是的。我正在开发一项功能以使这变得更简单。

    至于那个 UnauthenticatedException,你可以忽略它。这来自“管理框架”,它尝试检查身份验证令牌,即使它不涉及框架的 oauth 安全性(仅 api 密钥安全性)。

    【讨论】:

      猜你喜欢
      • 2017-10-09
      • 2014-10-11
      • 2017-05-26
      • 1970-01-01
      • 2011-12-25
      • 1970-01-01
      • 2017-03-23
      • 1970-01-01
      • 2017-08-30
      相关资源
      最近更新 更多