Apache 超集和 Auth0 returns "unexpected keyword argument 'scope'"

Apache Superset and Auth0 returns "unexpected keyword argument 'scope'"

前段时间,我使用 AWS Cognito 成功地将 Superset 身份验证与 Oauth 集成。

现在我正尝试对 Auth0 做同样的事情,重新使用以前的配置并根据 Auth0 文档更改端点。

不幸的是,登录失败并且 Superset 的日志 returns 显示以下消息:

2021-10-20 10:30:48,886:ERROR:flask_appbuilder.security.views:Error on OAuth authorize: request() got an unexpected keyword argument 'scope'

这是superset_config.py中的Oauth配置:

from superset.security import SupersetSecurityManager

import json
import logging

logger = logging.getLogger(__name__)

class CustomSsoSecurityManager(SupersetSecurityManager):
    def oauth_user_info(self, provider, response=None):
        if provider == 'auth0':
            res = self.appbuilder.sm.oauth_remotes[provider].get('userinfo')
            if res.raw.status != 200:
                logger.error('Failed to obtain user info: %s', res.data)
                return
            me = json.loads(res._content)
            logger.warning(" user_data: %s", me)
            prefix = 'Superset'
            logging.warning("user_data: {0}".format(me))
            return {
                'username' : me['email'],
                'name' : me['name'],
                'email' : me['email'],
                'first_name': me['given_name'],
                'last_name': me['family_name'],
            }

AUTH_TYPE = AUTH_OAUTH
AUTH_USER_REGISTRATION = True
AUTH_USER_REGISTRATION_ROLE = "Public"

AUTH0_URL = os.getenv('AUTH0_URL')
AUTH0_CLIENT_KEY = os.getenv('AUTH0_CLIENT_KEY')
AUTH0_CLIENT_SECRET = os.getenv('AUTH0_CLIENT_SECRET')

OAUTH_PROVIDERS = [{
    'name':'auth0',
    'token_key': 'access_token',
    'icon':'fa-at',
    'url': AUTH0_URL,
    'remote_app': {
        'client_id': AUTH0_CLIENT_KEY,
        'client_secret': AUTH0_CLIENT_SECRET,
        'request_token_params': {
            'scope': 'email openid profile'
        },
        'response_type': 'token_id',
        'base_url': AUTH0_URL,
        'access_token_url': os.path.join(AUTH0_URL, 'oauth/token'),
        'authorize_url': os.path.join(AUTH0_URL, 'authorize'),
        'access_token_method':'POST',
        'request_token_url': os.path.join(AUTH0_URL, 'oauth/token'),
        'api_base_url': AUTH0_URL,
        }
    }
]

CUSTOM_SECURITY_MANAGER = CustomSsoSecurityManager

我已经为 response_type(代码、令牌、token_id)尝试了不同的值。

还尝试将 request_token_url 留空,在这种情况下,错误发生变化,因为用户数据似乎是一个空字典:

2021-10-13 15:52:10,358:WARNING:superset_config: user_data: {}
2021-10-13 15:52:10,358:WARNING:root:user_data: {}
2021-10-13 15:52:10,358:ERROR:flask_appbuilder.security.views:Error returning OAuth user info: 'email'

所以我假设令牌实际上已返回,我不明白为什么 Flask 抱怨属性“范围”。

也尝试了 ,因为它看起来与我的问题非常相似,但是 none 这些配置对我有用。

希望您有两个文件 custom_sso_security_manager.py 和 superset_config.py

你可以从 return 中删除以下两行并尝试 (custom_sso_security_manager.py).

'first_name': me['given_name'],
'last_name': me['family_name'],

根据 Flask Documentation, 尝试使用 client_kwargs 而不是 request_token_params 键。

样本:

{
    'name':'google',
    'icon':'fa-google',
    'token_key':'access_token',
    'remote_app': {
            'client_id':'GOOGLE_KEY',
            'client_secret':'GOOGLE_SECRET',
            'api_base_url':'https://www.googleapis.com/oauth2/v2/',
            'client_kwargs':{
              'scope': 'email profile'
            },
            'request_token_url':None,
            'access_token_url':'https://accounts.google.com/o/oauth2/token',
            'authorize_url':'https://accounts.google.com/o/oauth2/auth'
    }
},

虽然我接受了Kamal的回答,但这是供将来参考。

事实证明,设置请求令牌范围的正确参数是 client_kwargs 而不是 request_token_params

这是根据 Auth0 验证 Superset 的有效配置:

## Enable OAuth authentication
from flask_appbuilder.security.manager import (
    AUTH_OAUTH,
)

from superset.security import SupersetSecurityManager

import json
import logging
import string
import random

nonce = ''.join(random.choices(string.ascii_uppercase + string.digits + string.ascii_lowercase, k = 30))

logger = logging.getLogger(__name__)

class CustomSsoSecurityManager(SupersetSecurityManager):
    def oauth_user_info(self, provider, response=None):
        if provider == 'auth0':
            res = self.appbuilder.sm.oauth_remotes[provider].get('userinfo')
            if res.raw.status != 200:
                logger.error('Failed to obtain user info: %s', res.json())
                return
            me = res.json()
            return {
                'username' : me['email'],
                'name' : me['name'],
                'email' : me['email'],
            }

AUTH_TYPE = AUTH_OAUTH
AUTH_USER_REGISTRATION = True
AUTH_USER_REGISTRATION_ROLE = "Public"

AUTH0_URL = os.getenv('AUTH0_URL')
AUTH0_CLIENT_KEY = os.getenv('AUTH0_CLIENT_KEY')
AUTH0_CLIENT_SECRET = os.getenv('AUTH0_CLIENT_SECRET')

OAUTH_PROVIDERS = [
  {   'name':'auth0',
      'token_key':'access_token',
      'icon':'fa-at',
      'remote_app': {
          'api_base_url': AUTH0_URL,
          'client_id': AUTH0_CLIENT_KEY,  
          'client_secret': AUTH0_CLIENT_SECRET, 
          'server_metadata_url': os.path.join(AUTH0_URL, '.well-known/openid-configuration'),
          'client_kwargs': {
              'scope': 'openid profile email'
          },
         'response_type': 'code token',
         'nonce': nonce,
      }
  }
]

CUSTOM_SECURITY_MANAGER = CustomSsoSecurityManager