IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Python知识库 -> DjangoRestFramework 使用 python-social-auth 实现第三方登录 -> 正文阅读

[Python知识库]DjangoRestFramework 使用 python-social-auth 实现第三方登录

本文为 social-auth-app-django 使用记录。(官方文档)

0. 前言

前提:有两个网站,记为网站A、网站B,两个网站有各自的用户系统,现在网站B要实现使网站A的用户无需注册直接登录自己的网站,这里就要用到第三方登录。

环境: Django == 3.x??social-auth-app-django == 4.0.0

1. 安装?

pip install social-auth-app-django

2. 使用

网站A该篇文章的 provider 项目,即 OAuth provider(提供方);?

创建 Django 项目(网站B),即 OAuth consumer(使用方),网站B目录树如下图:

├─manage.py
├─social
│  │  asgi.py
│  │  settings.py
│  │  urls.py
│  │  wsgi.py
│  └─ __init__.py
└─users
   │  admin.py
   │  apps.py
   │  backends.py
   │  models.py
   │  tests.py
   │  views.py
   └─ __init__.py

并进行相关配置:?

# social/settings.py
INSTALLED_APPS = [
    ...
    'users',
    'social_django',    # add
]

SOCIAL_AUTH_ADMIN_USER_SEARCH_FIELDS = ['username', 'email']

# SOCIAL_AUTH_要使用登录模块的名称大写_KEY
# 登录模块名对应为第三步中自定义后端的 name 属性
SOCIAL_AUTH_DJANGO_KEY = 'local'
SOCIAL_AUTH_DJANGO_SECRET = 'local'

# 登录成功后跳转页面
LOGIN_REDIRECT_URL = '/admin/'        

# 获取授权码的标识
PARTIAL_PIPELINE_TOKEN_NAME = 'code'

AUTHENTICATION_BACKENDS = (
    'users.backends.djangoOauth2',                  # 自定义第三方登录认证
    'django.contrib.auth.backends.ModelBackend',    # django 默认登录认证
)

# 获取用户详细的信息
SOCIAL_AUTH_PIPELINE = (
    'social_core.pipeline.social_auth.social_details',
    'social_core.pipeline.social_auth.social_uid',
    'social_core.pipeline.social_auth.social_user',
    'social_core.pipeline.user.get_username',
    'social_core.pipeline.user.create_user',
    'social_core.pipeline.social_auth.associate_user',
    'social_core.pipeline.social_auth.load_extra_data',
    'social_core.pipeline.user.user_details',
)

?3.自定义认证后端?

配置文件 settings.py 中的?AUTHENTICATION_BACKENDS?下自定义了一个 djangoOauth2,代码实现如下:

import requests
from social_core.backends.oauth import BaseOAuth2


class djangoOauth2(BaseOAuth2):
    name = 'django'    # 调用的第三方名称, 如 google
    AUTHORIZATION_URL = 'http://127.0.0.1:8000/o/authorize/'   # 获取授权码的路由
    ACCESS_TOKEN_URL = 'http://127.0.0.1:8000/o/token/'        # 获取 token 的路由      
    ACCESS_TOKEN_METHOD = 'POST'    # 获取 token 的请求方式
    RESPONSE_TYPE = 'code'
    REDIRECT_STATE = False
    STATE_PARAMETER = False
    EXTRA_DATA = [
        ('id', 'id'),
        ('username', 'username'),
    ]

    def get_user_details(self, response):
        """Return user details from Django siteA. """
        print('get_user_details')
        return response

    def user_data(self, access_token, response=None, *args, **kwargs):
        """Return user data"""
        # 本处使用了用户id获取用户详细信息
        # 由于网站A(provider)项目中返回的 token 信息并不包含 id 信息
        # 因此这里网站A 自定义了返回 token信息(代码见下)
        url = 'http://127.0.0.1:8000/users/{}'.format(response['id'])
        headers = {'Authorization': 'Bearer ' + access_token}
        user_data = self.get_json(
            url=url,
            method='GET',
            headers=headers
        )
        print(user_data)
        return user_data

注意:此处为网站A(provider)中自定义的 token 代码:

# provider/users/views.py
import json

from django.http import HttpResponse
from django.utils.decorators import method_decorator
from django.views.decorators.debug import sensitive_post_parameters
from oauth2_provider.models import get_access_token_model
from oauth2_provider.signals import app_authorized
from oauth2_provider.views import TokenView


class CustomTokenView(TokenView):
    """ 自定义返回令牌 """

    @method_decorator(sensitive_post_parameters("password"))
    def post(self, request, *args, **kwargs):
        url, headers, body, status = self.create_token_response(request)
        if status == 200:
            body = json.loads(body)
            access_token = body.get("access_token")
            if access_token is not None:
                token = get_access_token_model().objects.get(token=access_token)
                app_authorized.send(sender=self, request=request, token=token)
                body['id'] = token.user.id
                body = json.dumps(body)
        response = HttpResponse(content=body, status=status)

        for k, v in headers.items():
            response[k] = v
        return response

# provider/urls.py
import oauth2_provider.views as oauth2_views
from django.conf import settings
from django.contrib import admin
from django.urls import path, include

from users.utils import CustomTokenView
from users.views import UserList, UserDetails

# OAuth2 provider endpoints
oauth2_endpoint_views = [
    path('authorize/', oauth2_views.AuthorizationView.as_view(), name="authorize"),
    # 这里使用自定义 token 信息
    path('token/', CustomTokenView.as_view(), name="token"),    
    path('revoke_token/', oauth2_views.RevokeTokenView.as_view(), name="revoke-token"),
]

if settings.DEBUG:
    # OAuth2 Application Management endpoints
    oauth2_endpoint_views += [
        path('applications/', oauth2_views.ApplicationList.as_view(), name="list"),
        path('applications/register/', oauth2_views.ApplicationRegistration.as_view(), name="register"),
        path('applications/<pk>/', oauth2_views.ApplicationDetail.as_view(), name="detail"),
        path('applications/<pk>/delete/', oauth2_views.ApplicationDelete.as_view(), name="delete"),
        path('applications/<pk>/update/', oauth2_views.ApplicationUpdate.as_view(), name="update"),
    ]

    # OAuth2 Token Management endpoints
    oauth2_endpoint_views += [
        path('authorized-tokens/', oauth2_views.AuthorizedTokensListView.as_view(), name="authorized-token-list"),
        path('authorized-tokens/<pk>/delete/', oauth2_views.AuthorizedTokenDeleteView.as_view(),
             name="authorized-token-delete"),
    ]

urlpatterns = [
    path('admin/', admin.site.urls),
    # path('o/',  include('oauth2_provider.urls', namespace='oauth2_provider')),  # before
    path('o/', include((oauth2_endpoint_views, 'oauth2_provider'), namespace="oauth2_provider")),  # now
    path('users/', UserList.as_view()),
    path('users/<pk>/', UserDetails.as_view()),
]

?4. 在网站A中注册网站B

注意:此时网站A在8000端口运行,网站B在8001端口运行。

网站B要想调用网站A登录,则需要在网站A注册自己网站的信息,注册地址为:http://127.0.0.1:8000/o/applications/, 点击 New Applications 进行添加:

?

其中填写的 client_id?对应配置文件 settings.py 中的 SOCIAL_AUTH_DJANGO_KEY, client_secret 对应?SOCIAL_AUTH_DJANGO_SECRRT。

授权类型为授权码类型(authorization);

重定向地址为 http://127.0.0.1:8001/complete/django/,其中 8001 为网站B运行的端口,django 为自定义认证后端类中的 name。

5. 调用第三方登录

在浏览器中输入 http://127.0.0.1:8001/login/django/,

会发现重定向路由为 http://127.0.0.1:8000/o/authorize/?client_id=local&redirect_uri=http://127.0.0.1:8001/complete/django/&response_type=code,

输入网站A中的用户名密码,点击授权(Authorize),?

会发现网址重定向到了 http://127.0.0.1:8001/admin/login/?next=/admin/,红字表示已经使用网站A中的 admin 用户登录成功,但是该用户没有访问该页面的权限(superuser才可以访问)。

?同时Pycharm中会输出:

?创建网站B的超级用户(social)并查看 http://127.0.0.1:8001/admin 界面:

  Python知识库 最新文章
Python中String模块
【Python】 14-CVS文件操作
python的panda库读写文件
使用Nordic的nrf52840实现蓝牙DFU过程
【Python学习记录】numpy数组用法整理
Python学习笔记
python字符串和列表
python如何从txt文件中解析出有效的数据
Python编程从入门到实践自学/3.1-3.2
python变量
上一篇文章      下一篇文章      查看所有文章
加:2021-07-14 10:49:15  更:2021-07-14 10:49:52 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/15 1:14:05-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码