Django 和 Facebook 身份验证集成

119 阅读3分钟

我们正在创建一个 Django 网站,并希望集成 Facebook 身份验证功能,以便用户可以通过 Facebook 账号登录我们的网站。除此之外,网站本身也提供传统的 Django 身份验证系统,即用户可以使用用户名和密码登录。目前,我们已经能够成功实现 Facebook 登录功能,并且可以获取到用户的姓名、电子邮件等信息。现在的问题是,我们该如何将这些 Facebook 账号与 Django 身份验证系统合并起来,以便用户能够使用同一个账号登录 Facebook 和 Django?

2、解决方案

以下是在 Django 中将 Facebook 身份验证与 Django 身份验证合并的解决方案:

1. 创建模型来存储 Facebook 信息

我们需要创建一个模型来存储 Facebook 的身份信息,这个模型可以命名为 SocialAccount,其中包含以下字段:

class SocialAccount(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    provider = models.CharField(max_length=32)
    provider_user_id = models.CharField(max_length=255)
    access_token = models.CharField(max_length=255)

2. 将 Facebook 账号与 Django 用户关联

当用户通过 Facebook 登录时,我们需要创建一个对应的 Django 用户对象,并将这个用户对象与 SocialAccount 关联起来。这样做是为了让用户能够使用同一个账号登录 Facebook 和 Django。

# 根据 Facebook 信息创建 Django 用户对象
user = User.objects.create_user(username, email, is_active=False)

# 创建 SocialAccount 对象并关联 Django 用户
social_account = SocialAccount(
    user=user,
    provider='facebook',
    provider_user_id=facebook_user_id,
    access_token=access_token
)
social_account.save()

3. 自定义认证后端

为了能够使用 Facebook 账号登录 Django,我们需要创建一个自定义的认证后端。这个后端需要继承 django.contrib.auth.backends.ModelBackend 类,并实现 authenticate()get_user() 方法。

class SocialAuthBackend(ModelBackend):
    def authenticate(self, request, provider=None, provider_user_id=None, access_token=None):
        try:
            social_account = SocialAccount.objects.get(provider=provider, provider_user_id=provider_user_id)
            user = social_account.user
            # 由于用户是通过社交账号登录的,因此将其密码置为不可用
            user.set_unusable_password()
            return user
        except SocialAccount.DoesNotExist:
            return None

    def get_user(self, user_id):
        try:
            user = User.objects.get(pk=user_id)
            return user
        except User.DoesNotExist:
            return None

4. 在 Django 中注册自定义认证后端

在 Django 的 settings.py 文件中,我们需要将自定义认证后端注册到认证后端列表中。

AUTHENTICATION_BACKENDS = [
    'django.contrib.auth.backends.ModelBackend',
    'path.to.SocialAuthBackend',
]

5. 配置 URL

最后,我们需要在 Django 的 URL 配置文件中添加一个 URL,用于处理 Facebook 登录回调。

from django.contrib.auth import views as auth_views
from path.to.views import facebook_login

urlpatterns = [
    path('login/facebook/', facebook_login, name='facebook_login'),
    path('logout/', auth_views.LogoutView.as_view(), name='logout'),
]

3、代码举例:

# 生成 Facebook 登录 URL
login_url = facebook.make_login_url(
    client_id=settings.FACEBOOK_APP_ID,
    redirect_uri=settings.FACEBOOK_REDIRECT_URI,
    scope=['email']
)

def facebook_login(request):
    # 从 Facebook 登录回调中获取授权码
    code = request.GET.get('code')
    if not code:
        return HttpResponseBadRequest("Missing code parameter.")

    # 使用授权码获取访问令牌
    access_token = facebook.get_access_token_from_code(
        client_id=settings.FACEBOOK_APP_ID,
        client_secret=settings.FACEBOOK_APP_SECRET,
        redirect_uri=settings.FACEBOOK_REDIRECT_URI,
        code=code
    )

    # 使用访问令牌获取用户信息
    user_info = facebook.get_user_info(access_token)

    # 根据用户信息查找或创建 Django 用户
    try:
        user = User.objects.get(email=user_info['email'])
    except User.DoesNotExist:
        user = User.objects.create_user(user_info['email'], is_active=False)

    # 创建 SocialAccount 对象并关联 Django 用户
    social_account = SocialAccount(
        user=user,
        provider='facebook',
        provider_user_id=user_info['id'],
        access_token=access_token
    )
    social_account.save()

    # 将用户认证为激活状态
    user.is_active = True
    user.save()

    # 将用户登录到 Django
    auth_login(request, user)

    return HttpResponseRedirect('/')