You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Apache Superset集成Azure Entra ID登出重登遇502错误排查

问题描述

我已成功为Apache Superset配置Azure Entra ID双因素认证,但登出后再次登录时出现502 Bad Gateway错误,浏览器地址栏显示:https://my-app.com/login/azure?next=,且Superset似乎未在登出时清除缓存,只有手动清除浏览器历史记录后才能正常登录。

Nginx配置

server {
    server_name my-app.rw;

    location / {
        proxy_pass http://127.0.0.1:8088;  # Changed to localhost
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_redirect http:// $scheme://;
    }

    location = /logout {
        proxy_pass http://127.0.0.1:8088/logout;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_redirect http:// $scheme://;
        proxy_redirect off;  # Critical for Azure AD
    }

    listen 443 ssl;
    ssl_certificate /etc/letsencrypt/live/my-app.rw/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/my-app.rw/privkey.pem;
    include /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
}

superset_config.py配置

class CustomSecurityManager(SupersetSecurityManager):

    def oauth_user_info(self, provider, response=None):
    
        if provider != 'azure':
            # Handle other providers or return empty
            return {}
        
        try:
            # Log the response for debugging
            logger.debug(f"OAuth response for {provider}: {response}")

          
            remote = self.appbuilder.sm.oauth_remotes[provider]

            # Log the authorize URL (initial redirect to Azure AD)
            logger.debug(f"Authorize URL: {remote.authorize_url}")  # Should match Azure AD


            # Log the token exchange URL
            logger.debug(f"Token URL: {remote.access_token_url}")  # Should be Azure AD's /token endpoint
            
            
            # More robust token handling
            headers = {}
            if response.get('access_token'):
                headers['Authorization'] = f"Bearer {response.get('access_token')}"
            
            # Make the API request
            me = remote.get('https://graph.microsoft.com/v1.0/me', token=response, headers=headers)
            
            # Check for success
            if me.status_code != 200:
                logger.error(f"Microsoft Graph API error: {me.status_code} - {me.text}")
                return {}
            
            # Parse the response
            user_data = me.json()
            logger.debug(f"User data from Microsoft Graph: {user_data}")
            
            # Extract user information
            email = user_data.get('mail')
            if not email:
                upn = user_data.get('userPrincipalName')
                if upn:
                    email = upn.split('#EXT#')[0].replace('_', '@')

            existing_user = self.appbuilder.get_session.query(User).filter_by(email=email).first()
            username = existing_user.username if existing_user else email

            return {
                'email': email,
                'username': username,
                'first_name': user_data.get('givenName', ''),
                'last_name': user_data.get('surname', ''),
            }
        except Exception as e:
            # Log the full error with traceback
            logger.exception(f"OAuth error for {provider}: {str(e)}")
            # Return empty dict instead of raising to prevent authentication failures
            return {}
    


class CustomAuthDBView(AuthDBView):
    @expose('/logout')
    def logout(self):
        # Clear local session
        self.appbuilder.sm.logout_user()
        # Redirect to Azure AD logout
        return redirect(
            "https://login.microsoftonline.com/974x/oauth2/v2.0/logout"
            "?post_logout_redirect_uri=https://my-app.rw/login"
        )


CUSTOM_SECURITY_MANAGER = CustomSecurityManager


# Register the view
APP_BUILDER_VIEWS = [CustomAuthDBView]

ENABLE_PROXY_FIX = True 

AUTH_TYPE = AUTH_OAUTH

OAUTH_PROVIDERS = [
    {
            "name": "azure",
            "icon": "fa-windows",
            "token_key": "access_token",
            "remote_app": {
                "client_id": "0722xxx", 
                "client_secret": "ky8xxx",
                "api_base_url": "https://graph.microsoft.com/v1.0/",
                "server_metadata_url": "https://login.microsoftonline.com/974xx/v2.0/.well-known/openid-configuration",
                "redirect_uri": "https://my-app.rw/oauth-authorized/azure",
               "logout_url": (
                    "https://login.microsoftonline.com/9xxx/oauth2/v2.0/logout"
                    "?post_logout_redirect_uri=https://my-app.rw/logout"
                ),
                "client_kwargs": {
                    "scope": "openid profile email User.Read",
                },
                "request_token_url": None,
                "access_token_url": "https://login.microsoftonline.com/974x/oauth2/v2.0/token",  
                "authorize_url": "https://login.microsoftonline.com/974x/oauth2/v2.0/authorize", 
            },
        }
    ]

解决方案

1. 修复登出流程的重定向冲突

当前自定义登出逻辑与OAUTH_PROVIDERS中的logout_url配置存在循环重定向问题,导致Nginx返回502错误:

  • 移除OAUTH_PROVIDERS中的logout_url配置,让自定义登出逻辑完全接管流程
  • 确保Azure AD的post_logout_redirect_uri指向登录页而非/logout

修改后的OAUTH_PROVIDERS片段:

OAUTH_PROVIDERS = [
    {
            "name": "azure",
            "icon": "fa-windows",
            "token_key": "access_token",
            "remote_app": {
                "client_id": "0722xxx", 
                "client_secret": "ky8xxx",
                "api_base_url": "https://graph.microsoft.com/v1.0/",
                "server_metadata_url": "https://login.microsoftonline.com/974xx/v2.0/.well-known/openid-configuration",
                "redirect_uri": "https://my-app.rw/oauth-authorized/azure",
                # 移除logout_url配置项
                "client_kwargs": {
                    "scope": "openid profile email User.Read",
                },
                "request_token_url": None,
                "access_token_url": "https://login.microsoftonline.com/974x/oauth2/v2.0/token",  
                "authorize_url": "https://login.microsoftonline.com/974x/oauth2/v2.0/authorize", 
            },
        }
    ]

2. 强化会话清除逻辑

在自定义登出方法中,除了调用logout_user(),手动清除Superset相关Cookie,避免缓存残留:

修改CustomAuthDBView的logout方法:

class CustomAuthDBView(AuthDBView):
    @expose('/logout')
    def logout(self):
        # 清除本地会话
        self.appbuilder.sm.logout_user()
        # 重定向到Azure AD登出页
        response = redirect(
            "https://login.microsoftonline.com/974x/oauth2/v2.0/logout"
            "?post_logout_redirect_uri=https://my-app.rw/login"
        )
        # 清除Superset会话Cookie
        response.delete_cookie('session')
        response.delete_cookie('superset_session')
        return response

3. 调整Nginx缓存规则

确保Nginx不对登录、登出及OAuth授权路径进行缓存:

修改Nginx的location /块:

location / {
    proxy_pass http://127.0.0.1:8088;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection 'upgrade';
    proxy_set_header Host $host;
    proxy_cache_bypass $http_upgrade;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_redirect http:// $scheme://;
    # 排除关键路径的缓存
    proxy_no_cache $request_uri ~* (/login|/logout|/oauth-authorized);
    proxy_cache_bypass $request_uri ~* (/login|/logout|/oauth-authorized);
}

简化location = /logout块配置:

location = /logout {
    proxy_pass http://127.0.0.1:8088/logout;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_redirect off;
}

4. 验证Azure AD应用配置

  • 确认Azure AD应用的重定向URI包含https://my-app.rw/oauth-authorized/azure
  • 将https://my-app.rw/login添加到Azure AD应用的已注销重定向URI列表中

5. 重启服务验证

  1. 重启Nginx:sudo systemctl restart nginx
  2. 重启Superset:superset restart
  3. 测试登出后重新登录,确认502错误消失,无需手动清除缓存即可正常登录

内容的提问来源于stack exchange,提问作者Mo1

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 06:24:50