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

如何基于AngularJS前端与DRF后端实现带JWT返回的社交登录功能

嘿,我来帮你一步步实现这个AngularJS + DRF的社交登录方案,完全贴合你的需求,咱们分前端和后端两部分来拆解:

整体流程对齐

先确认下咱们的核心流程,和你描述的完全一致:

  1. 用户点击FB/Google登录按钮,完成第三方授权,拿到access_token
  2. AngularJS把access_token和登录类型(FB/Google)POST给DRF后端
  3. 后端验证第三方access_token的合法性,获取用户的名、姓、邮箱
  4. 后端查找是否已有关联该第三方账号的用户,没有则创建新用户
  5. 后端生成JWT令牌,以HttpOnly Cookie形式返回给前端
  6. 后续所有API请求,浏览器自动带上JWT Cookie,无需再次走第三方登录

后端DRF实现步骤

1. 安装依赖包

先装必要的工具库,在你的Django项目根目录执行:

pip install djangorestframework djangorestframework-simplejwt requests
  • djangorestframework-simplejwt:用来生成和验证JWT令牌
  • requests:用来调用FB/Google的token验证API

2. 配置SimpleJWT和DRF

在settings.py里添加以下配置:

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

# SimpleJWT配置,重点设置Cookie相关参数
from datetime import timedelta
SIMPLE_JWT = {
    'ACCESS_TOKEN_LIFETIME': timedelta(hours=24),
    'REFRESH_TOKEN_LIFETIME': timedelta(days=7),
    # 把令牌放在Cookie里返回
    'AUTH_COOKIE': 'access_token',
    'AUTH_COOKIE_REFRESH': 'refresh_token',
    'AUTH_COOKIE_SECURE': True,  # 生产环境设为True,必须HTTPS
    'AUTH_COOKIE_HTTPONLY': True,  # 关键!防止XSS攻击,JS无法读取
    'AUTH_COOKIE_SAMESITE': 'Lax',  # 防止CSRF,根据需求选Strict/Lax
}

# 别忘了把rest_framework和rest_framework_simplejwt加入INSTALLED_APPS
INSTALLED_APPS = [
    # ... 其他已有的app
    'rest_framework',
    'rest_framework_simplejwt',
]

3. 创建社交登录视图

在你的app里新建views.py的视图函数,处理前端传来的access_token:

from django.http import JsonResponse
from django.contrib.auth import get_user_model
from rest_framework.views import APIView
from rest_framework import status
import requests

User = get_user_model()

class SocialLoginView(APIView):
    def post(self, request):
        provider = request.data.get('provider')  # 'facebook' 或 'google'
        access_token = request.data.get('access_token')
        
        if not provider or not access_token:
            return JsonResponse({'error': '缺少必要参数'}, status=status.HTTP_400_BAD_REQUEST)
        
        # 1. 调用第三方API验证token并获取用户信息
        user_info = None
        if provider == 'facebook':
            # FB的验证接口,获取用户的名、姓、邮箱
            fb_url = f"https://graph.facebook.com/me?access_token={access_token}&fields=first_name,last_name,email,id"
            response = requests.get(fb_url)
            if response.status_code != 200:
                return JsonResponse({'error': 'FB令牌无效'}, status=status.HTTP_400_BAD_REQUEST)
            user_info = response.json()
        elif provider == 'google':
            # Google的验证接口,注意如果是id_token的话用tokeninfo接口,access_token用userinfo接口
            google_url = f"https://www.googleapis.com/oauth2/v3/userinfo?access_token={access_token}"
            response = requests.get(google_url)
            if response.status_code != 200:
                return JsonResponse({'error': 'Google令牌无效'}, status=status.HTTP_400_BAD_REQUEST)
            user_info = response.json()
        else:
            return JsonResponse({'error': '不支持的登录方式'}, status=status.HTTP_400_BAD_REQUEST)
        
        # 2. 提取用户信息
        first_name = user_info.get('first_name') or user_info.get('given_name')
        last_name = user_info.get('last_name') or user_info.get('family_name')
        email = user_info.get('email')
        provider_uid = user_info.get('id')
        
        if not email:
            return JsonResponse({'error': '第三方账号未绑定邮箱'}, status=status.HTTP_400_BAD_REQUEST)
        
        # 3. 查找或创建用户,这里建议用关联表记录第三方账号(避免重复)
        # 先查是否已有该第三方账号关联的用户
        from django.db.models import Q
        # 假设你有一个SocialAccount模型,字段:user(外键)、provider(字符串)、uid(字符串)
        try:
            social_account = SocialAccount.objects.get(provider=provider, uid=provider_uid)
            user = social_account.user
        except SocialAccount.DoesNotExist:
            # 没有的话,先查邮箱是否已存在用户
            try:
                user = User.objects.get(email=email)
                # 关联已有用户和第三方账号
                SocialAccount.objects.create(user=user, provider=provider, uid=provider_uid)
            except User.DoesNotExist:
                # 创建新用户
                user = User.objects.create(
                    first_name=first_name,
                    last_name=last_name,
                    email=email,
                    username=email.split('@')[0]  # 用邮箱前缀当用户名,或者生成随机字符串
                )
                user.set_unusable_password()  # 社交登录用户不需要密码
                user.save()
                # 关联第三方账号
                SocialAccount.objects.create(user=user, provider=provider, uid=provider_uid)
        
        # 4. 生成JWT令牌并以Cookie返回
        from rest_framework_simplejwt.tokens import RefreshToken
        refresh = RefreshToken.for_user(user)
        response = JsonResponse({'message': '登录成功', 'user': {'email': user.email, 'name': f"{user.first_name} {user.last_name}"}})
        
        # 设置Access Token Cookie
        response.set_cookie(
            key='access_token',
            value=str(refresh.access_token),
            expires=SIMPLE_JWT['ACCESS_TOKEN_LIFETIME'],
            secure=SIMPLE_JWT['AUTH_COOKIE_SECURE'],
            httponly=SIMPLE_JWT['AUTH_COOKIE_HTTPONLY'],
            samesite=SIMPLE_JWT['AUTH_COOKIE_SAMESITE']
        )
        # 可选:设置Refresh Token Cookie,用来刷新令牌
        response.set_cookie(
            key='refresh_token',
            value=str(refresh),
            expires=SIMPLE_JWT['REFRESH_TOKEN_LIFETIME'],
            secure=SIMPLE_JWT['AUTH_COOKIE_SECURE'],
            httponly=SIMPLE_JWT['AUTH_COOKIE_HTTPONLY'],
            samesite=SIMPLE_JWT['AUTH_COOKIE_SAMESITE']
        )
        
        return response

注意:需要创建SocialAccount模型,在app的models.py里:

from django.db import models
from django.contrib.auth import get_user_model

User = get_user_model()

class SocialAccount(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='social_accounts')
    provider = models.CharField(max_length=20)  # 'facebook', 'google'
    uid = models.CharField(max_length=100, unique=True)  # 第三方账号的唯一ID

    class Meta:
        unique_together = ('provider', 'uid')

然后执行python manage.py makemigrations和python manage.py migrate创建表。

4. 配置URL路由

在项目的urls.py里添加:

from django.urls import path
from .views import SocialLoginView

urlpatterns = [
    # ... 其他路由
    path('api/social-login/', SocialLoginView.as_view(), name='social-login'),
]

前端AngularJS实现步骤

1. 集成第三方登录SDK

在你的index.html里引入FB和Google的SDK:

<!-- Facebook SDK -->
<script async defer crossorigin="anonymous" 
        src="https://connect.facebook.net/en_US/sdk.js#xfbml=1&version=v18.0&appId=你的FB_APP_ID&autoLogAppEvents=1" 
        nonce="随机字符串"></script>

<!-- Google Login SDK -->
<script src="https://accounts.google.com/gsi/client" async defer></script>

记得替换你的FB_APP_ID为你在FB开发者平台创建的应用ID,Google的话需要在Google Cloud控制台创建OAuth 2.0客户端ID。

2. 创建登录控制器和按钮

在AngularJS的controller里写登录逻辑:

angular.module('yourApp', [])
.controller('LoginController', function($scope, $http) {
    // 初始化FB SDK
    window.fbAsyncInit = function() {
        FB.init({
            appId      : '你的FB_APP_ID',
            cookie     : true,
            xfbml      : true,
            version    : 'v18.0'
        });
    };

    // Facebook登录
    $scope.facebookLogin = function() {
        FB.login(function(response) {
            if (response.status === 'connected') {
                // 拿到FB的access_token
                const accessToken = response.authResponse.accessToken;
                // 发送请求到后端
                $http.post('/api/social-login/', {
                    provider: 'facebook',
                    access_token: accessToken
                }).then(function(res) {
                    console.log('登录成功', res.data);
                    // 这里可以跳转到首页或者更新用户状态
                    window.location.href = '/dashboard';
                }).catch(function(err) {
                    console.error('登录失败', err.data);
                    alert(err.data.error || '登录出错,请重试');
                });
            } else {
                alert('用户未授权');
            }
        }, {scope: 'email public_profile'}); // 请求必要的权限
    };

    // Google登录
    $scope.googleLogin = function() {
        // 初始化Google Auth
        google.accounts.id.initialize({
            client_id: '你的GOOGLE_CLIENT_ID',
            callback: handleGoogleResponse
        });

        // 弹出登录框
        google.accounts.id.prompt();

        function handleGoogleResponse(response) {
            // 这里拿到的是id_token,如果你需要access_token的话,用gapi.auth2方式
            const auth2 = gapi.auth2.getAuthInstance();
            auth2.signIn().then(function(googleUser) {
                const accessToken = googleUser.getAuthResponse().access_token;
                // 发送请求到后端
                $http.post('/api/social-login/', {
                    provider: 'google',
                    access_token: accessToken
                }).then(function(res) {
                    console.log('登录成功', res.data);
                    window.location.href = '/dashboard';
                }).catch(function(err) {
                    console.error('登录失败', err.data);
                    alert(err.data.error || '登录出错,请重试');
                });
            });
        }
    };
});

然后在HTML里添加登录按钮:

<div ng-controller="LoginController">
    <button ng-click="facebookLogin()">用Facebook登录</button>
    <button ng-click="googleLogin()">用Google登录</button>
</div>

3. 后续API请求处理

因为JWT是存在HttpOnly Cookie里的,浏览器会自动在后续的API请求中带上这个Cookie,所以你不需要手动处理JWT,直接用$http发送请求即可:

$http.get('/api/user-profile/').then(function(res) {
    console.log('当前用户信息', res.data);
});

后端的视图只要加上permission_classes = [IsAuthenticated]就能验证JWT的有效性。


注意事项
  • 安全性:生产环境一定要开启AUTH_COOKIE_SECURE=True,确保Cookie只在HTTPS下传输;HttpOnly属性必须开启,防止XSS攻击窃取令牌。
  • 邮箱冲突:如果用户之前用邮箱注册过,现在用社交登录,后端要处理这种情况,比如提示用户关联已有账号,或者自动关联(根据你的业务需求)。
  • 令牌刷新:可以实现一个刷新令牌的接口,当access_token过期时,用refresh_token获取新的access_token。
  • 错误处理:前端要处理后端返回的各种错误,比如令牌无效、第三方账号无邮箱等,给用户友好的提示。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 04:37:47