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

如何用dj-rest-auth、django-allauth和simplejwt支持多客户端接入

解决方案建议

核心思路:统一后端处理,避免重复配置

你不需要给每个客户端单独写SocialLoginView子类,也不需要让每个客户端自行在Google注册应用。正确的逻辑是让Django后端作为所有客户端的统一社交认证中间层,所有客户端共享同一个Google应用的client_id/secret,后端通过动态接收redirect_uri参数来支持多客户端,只要该URI已在Google控制台和django-allauth中注册。


步骤1:修改SocialLoginView,支持动态redirect_uri

去掉硬编码的callback_url,改为从请求参数中获取redirect_uri,同时让django-allauth验证该URI是否在允许列表中:

from dj_rest_auth.registration.views import SocialLoginView
from allauth.socialaccount.providers.google.views import GoogleOAuth2Adapter
from allauth.socialaccount.adapter import DefaultSocialAccountAdapter

class DynamicRedirectSocialAccountAdapter(DefaultSocialAccountAdapter):
    def is_valid_login_redirect_url(self, request, url):
        # 可自定义验证逻辑,比如检查url是否在预设允许列表中
        # 也可直接依赖django-allauth后台配置的redirect_uri
        return super().is_valid_login_redirect_url(request, url)

class GoogleLogin(SocialLoginView):
    adapter_class = GoogleOAuth2Adapter
    client_class = OAuth2Client

    def get_callback_url(self, request, app):
        # 从请求参数中获取客户端传递的redirect_uri
        redirect_uri = request.data.get('redirect_uri') or request.query_params.get('redirect_uri')
        if redirect_uri:
            return redirect_uri
        # 可选: fallback到默认回调地址
        return super().get_callback_url(request, app)

# 在settings.py中配置自定义适配器
SOCIALACCOUNT_ADAPTER = 'your_app.adapters.DynamicRedirectSocialAccountAdapter'

这样一个/api/dj-rest-auth/google/端点就能支持所有已注册的redirect_uri,无需新增URL配置。


步骤2:配置Google控制台和django-allauth,添加所有允许的redirect_uri

  1. Google控制台:
    • 进入你的Google OAuth应用,在「授权重定向URI」中添加所有客户端的回调地址:
      • Web端:http://localhost:4200/callback(Angular)、http://localhost:8080/callback(Vue)等
      • 移动端(Flutter):使用自定义URL scheme,比如com.yourflutterapp://google-callback
  2. django-allauth后台:
    • 登录Django admin,进入Social Accounts > Social Applications找到你的Google应用
    • 关联对应站点,并确保「Redirect URIs」字段包含所有Google控制台中添加的URI

步骤3:不同客户端的适配流程

Web客户端(Angular/Vue)

  1. 客户端生成Google授权URL时,使用后端提供的Google client_id,指定自身的redirect_uri:
    const clientId = 'YOUR_GOOGLE_CLIENT_ID';
    const redirectUri = 'http://localhost:4200/callback';
    const authUrl = `https://accounts.google.com/o/oauth2/v2/auth?scope=email%20profile&access_type=offline&response_type=code&state=YOUR_RANDOM_STATE&redirect_uri=${encodeURIComponent(redirectUri)}&client_id=${clientId}`;
    window.location.href = authUrl;
    
  2. 客户端在回调端点获取code后,POST到Django的/api/dj-rest-auth/google/,同时携带redirect_uri参数:
    const code = new URLSearchParams(window.location.search).get('code');
    fetch('http://localhost:8000/api/dj-rest-auth/google/', {
      method: 'POST',
      headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
      body: new URLSearchParams({ code, redirect_uri: redirectUri }),
    })
    .then(res => res.json())
    .then(data => {
      localStorage.setItem('access_token', data.access_token);
    });
    

Flutter移动端

  1. 添加url_launcher、flutter_web_auth等依赖,处理自定义URL scheme跳转
  2. 配置Flutter项目的自定义URL scheme(比如com.yourflutterapp)
  3. 生成Google授权URL,使用自定义scheme作为redirect_uri:
    final clientId = 'YOUR_GOOGLE_CLIENT_ID';
    final redirectUri = 'com.yourflutterapp://google-callback';
    final authUrl = Uri.parse('https://accounts.google.com/o/oauth2/v2/auth')
        .replace(queryParameters: {
      'scope': 'email profile',
      'access_type': 'offline',
      'response_type': 'code',
      'state': 'YOUR_RANDOM_STATE',
      'redirect_uri': redirectUri,
      'client_id': clientId,
    });
    final result = await FlutterWebAuth.authenticate(
      url: authUrl.toString(),
      callbackUrlScheme: 'com.yourflutterapp',
    );
    final code = Uri.parse(result).queryParameters['code'];
    
  4. 将code和redirect_uriPOST到Django后端:
    final response = await http.post(
      Uri.parse('http://localhost:8000/api/dj-rest-auth/google/'),
      body: { 'code': code, 'redirect_uri': redirectUri },
    );
    final data = jsonDecode(response.body);
    // 保存token用于后续API请求
    

步骤4:结合simplejwt实现API认证

确保dj-rest-auth使用simplejwt作为token后端,返回JWT格式的access_token和refresh_token:

# settings.py配置
REST_FRAMEWORK = {
  'DEFAULT_AUTHENTICATION_CLASSES': (
    'rest_framework_simplejwt.authentication.JWTAuthentication',
  ),
}

REST_USE_JWT = True
JWT_AUTH_COOKIE = 'access_token'
JWT_AUTH_REFRESH_COOKIE = 'refresh_token'

客户端在API请求的Authorization头中携带JWT:

// Angular示例
const headers = new HttpHeaders({
  'Authorization': `Bearer ${localStorage.getItem('access_token')}`
});
this.http.get('http://localhost:8000/api/protected/', { headers }).subscribe(...);

关键注意事项

  • state参数:必须携带随机state参数防止CSRF攻击,客户端需验证回调返回的state与发送的一致
  • HTTPS:生产环境必须使用HTTPS,否则Google会拒绝授权请求
  • token刷新:客户端要处理access_token过期情况,用refresh_token调用/api/dj-rest-auth/token/refresh/获取新token

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 22:05:41