• django QQ认证登录


    一、开发环境

    django 1.10.2

    python3.5.2

    django-social-auth 0.3.6

    二、申请QQ互联 APPID及SECRECT_KEY

    大致步骤:

    1.成为QQ互联开发者

    2.创建应用

    3.获取应用app_id 及secret_key

    三、代码

    1.安装认证框架

    $ pip3 install social-auth-app-django
    2.在INSTALLED_APPS中添加应用(settings.py)

    INSTALLED_APPS = (
        ...
        'social_django',
        ...
    )
    

    3.更新数据库

    python3 managy.py migrate

    4.在认证后端添加QQ认证以及QQ互联的key和id(settings.py)

    AUTHENTICATION_BACKENDS = (
        ...
        'social_core.backends.qq.QQOAuth2', 
    )
    SOCIAL_AUTH_QQ_KEY = 'your qq app id,like some number,for examle 230402020' # QQ APP_ID
    SOCIAL_AUTH_QQ_SECRET = 'you qq seckey ,combined by letter with number,for examle: f123bas324' # QQ SECRECT_KEY
    SOCIAL_AUTH_QQ_USE_OPENID_AS_USERNAME = True
    
    5.添加根urls.py的URL路由

    urlpatterns = [
        ......
        url('', include('social_django.urls', namespace='social'))
    ]
    6.在需要登录的地方加上如下代码:

    <a href="{% url "social:begin" "qq" %}">QQ登录 <!-- 这个登录标识注意要满足QQ互联的要求 --></a>
    

    7.settings.py中的TEMPALTES如下:

    TEMPLATES = [
        {
            ...
            'OPTIONS': {
                ...
                'context_processors': [
                    ...
                    'social_django.context_processors.backends',
                    'social_django.context_processors.login_redirect',
                    ...
                ]
            }
        }
    ]

    四、可能出现的问题

    1.认证页面是空白页面

    解决方案,检查APPID和SECRET_KEY是否填写正确

    2.redirect_url不合法 10010

    解决方案,注意域名的一致性,此问题是由于http请求中url和QQ互联中的 回调地址不同引起的,


    https://graph.qq.com/oauth/show?which=Login&display=pc&redirect_uri=http://localhost.com:8080/complete/qq/&client_id=xxxx&response_type=code&state=xxxx


    在实际使用过程中出现同样问题,主要是因为网站使用了多个域名,使用www.czxxs.cn和czxxs.cn都能访问网站,此时可以把回调地址设置为两个地址,如下:

    再次尝试,错误消失

    3.用openid代替昵称存储在数据库,在settings.py中加上以下语句(避免QQ昵称相同引起用户存储错误)

    SOCIAL_AUTH_QQ_USE_OPENID_AS_USERNAME = True


    参考连接:http://python-social-auth.readthedocs.io/en/latest/configuration/django.html

    http://python-social-auth.readthedocs.io/en/latest/backends/qq.html


    备注:

    功能可以根据上面两个连接进行完善,有问题欢迎留言

    五、扩展(Pipeline管道),实现认证流程的自定义

    用途:在认证过程中,可以加入自己的函数,实现认证过程的定制化。

    原理:自定义的函数会收到当前进程传递的参数,包括strategy,user,和request,建议在定义函数的时候额外添加**kwargs参数来避免 未知参数错误。

    返回:管道(自定义的函数)可以返回dict或者None,如果返回其他内容,这些内容则会被看做 一个  response,然后会直接返回给客户端,Partial Pipeline会介绍原理)

    如果返回的dict,那么dict的值会合并到 kwargs参数中,然后传递给下一个pipeline,如果返回None将被看做返回了'{}'空的字典

    (认证管道)Authentication Pipeline

    认证流程的最后一步,是处理一系列可操作的管道,可以在管道中添加自定义的功能,也可以删除默认的管道。认证系统默认的管道是创建用户实例,然后从认证服务商处获取一些基本的信息。默认的管道如下:

    (
        # 从服务商获取用户信息,然后以一种简单的格式返回,用来将来创建用户使用
        # 有时候用户的信息已经在认证消息的 Response 响应中了,但是有时需要使用服务商提供的api
        'social_core.pipeline.social_auth.social_details',
    
        # 从服务商处获取 social uid,这个uid是服务商给用户的唯一标识
        'social_core.pipeline.social_auth.social_uid',
    
        # 验证当前认证流程是否合法,需要提供邮箱和域名白名单(好像没用到过,可以自己深入研究)
        'social_core.pipeline.social_auth.auth_allowed',
    
        # 判断当前认证账户是否已经关联到了网站用户、
        'social_core.pipeline.social_auth.social_user',
    
        # 为认证用户创建一个用户名,如果用户名冲突则在用户名后添加随机字符串
        'social_core.pipeline.user.get_username',
    
        # 给用户发送验证邮件,验证其邮箱的真实性,默认禁用
        # 'social_core.pipeline.mail.mail_validation',
    
        # 把 当前社交认证信息和其他 邮箱相似的用户关联起来,默认禁用
        # 'social_core.pipeline.social_auth.associate_by_email',
    
        #如果没有发现用户账户则创建用户(以social user的信息创建)
        'social_core.pipeline.user.create_user',
    
        #创建将社交帐户与用户关联的记录。
        'social_core.pipeline.social_auth.associate_user',
    
        #使用settings.py指定的值(和access_token等默认值)填充社交记录中的extra_data字段。
        'social_core.pipeline.social_auth.load_extra_data',
    
        #使用来自auth服务的任何更改的信息更新用户记录。
        'social_core.pipeline.user.user_details',
    )
    可以在setting中通过设置SOCIAL_AUTH_PIPELINE来覆盖默认的管道。例如可以通过设置如下变量来达到,
    不创建用户,只与已经存在的用户关联的目的。

    SOCIAL_AUTH_PIPELINE = (
        'social_core.pipeline.social_auth.social_details',
        'social_core.pipeline.social_auth.social_uid',
        'social_core.pipeline.social_auth.auth_allowed',
        'social_core.pipeline.social_auth.social_user',
        'social_core.pipeline.social_auth.associate_user',
        'social_core.pipeline.social_auth.load_extra_data',
        'social_core.pipeline.user.user_details',
    )

    这是在用户已经授权的情况下可以通过这种方式来关联用户,因此在dict中会有 user这一键值。如果认证完全来自外部,必须提供一个用来产生 user键值的管道,比如:

    SOCIAL_AUTH_PIPELINE = (
        'social_core.pipeline.social_auth.social_details',
        'social_core.pipeline.social_auth.social_uid',
        'social_core.pipeline.social_auth.auth_allowed',
        'myapp.pipeline.load_user',
        'social_core.pipeline.social_auth.social_user',
        'social_core.pipeline.social_auth.associate_user',
        'social_core.pipeline.social_auth.load_extra_data',
        'social_core.pipeline.user.user_details',
    )
    也可以在setting中为每一个后端定制管道,例如 SOCIAL_AUTH_TWITTER_PIPELINE,指定的pipeline会覆盖默认的pipeline。

    每个pipeline函数会收到以下参数:

    1.strategy(包含访问当前存储,后端和请求的参数)

    2.社交认证端给出的userid

    3.社交认证端给出的用户信息

    4.is_new标志,默认值为False

    5.传递给 auth_complete方法的参数,默认的视图传递以下参数:

         ①当前登录的用户,如果未登录,是None

         ②当前的request

    Disconnection Pipeline(断开管道)

    和认证管道想反,当用户断开社交账户关联时的功能。

    比如,当用户断开所有社交账户关联时,需要用户填写登录密码(这种情况是针对,在认证管道中直接创建用户的情况,认证管道中存在'social_core.pipeline.user.create_user' 这条语句时才需要考虑断开管道,因为这个管道会直接用用户的社交 user_id创建用户名,但是却可以不存在密码如下图)。

    可以通过覆盖默认的断开管道,然后添加一个可以检查用户是否有密码的函数,如果不存在的话重定向到填写密码表单,然后继续执行断开流程。注意断开连接需要确保在POST方法下进行,一个简单的方法来确保这一点,是使您的表单POST到/ disconnect /并在管道功能中设置需要密码。


    覆盖断开管道的设置如下:

    SOCIAL_AUTH_DISCONNECT_PIPELINE = (
        # 验证社交关联是否可以断开(确保用户登录不会被断开 破坏?(compromised))
        'social_core.pipeline.disconnect.allowed_to_disconnect',
    
        # 收集需要断开的关联
        'social_core.pipeline.disconnect.get_entries',
    
        # 抽取acces_token
        'social_core.pipeline.disconnect.revoke_tokens',
    
        # 移除关联
        'social_core.pipeline.disconnect.disconnect',
    )
    
    
    同样也可以设置针对性管道如:SOCIAL_AUTH_TIWTTER_DISCONNECT_PIPELINE.

    Partial Pipeline(部分?管道)

    可以暂停管道返回到用户需要执行的动作,然后再继续执行。

    为了实现这一装饰器功能,需要用 @partial装饰器断开处理流程,partial装饰器文件位置位于social/pipeline/partial.py

    当需要返回到处理流程时,只需要把用户重定向到/complete/<backend>/或者/diconnect/<backend>/视图中,这样管道就会继续执行同样的功能,但是也可以中断处理流程。

    @partial把需要的数据存储到数据库中名为social_auth_partial的表中。此表包含着可以在将来从任何浏览器恢复的信息,同时会删除浏览器会话的旧依赖关系,从而防止浏览器之间的复制行为。

    partial数据根据UUID token来区分,token可以存储在session或者追加在url中以partial_token参数命名(默认值),库会从request中获取这些值,然后加载需要的值来让用户继续执行流程。

    pipeline功能函数会得到一个current_partial的实例,包含partial token和数据库中需要的数据

    为了使后端可以重定向到任何社交视图,只需要:

    backend = current_partial.backend
    通过下列语句可以覆盖默认的参数名称:

    SOCIAL_AUTH_PARTIAL_PIPELINE_TOKEN_NAME = '...
    示例:

    https://github.com/python-social-auth/social-examples

    Extending the Pipeline(扩展管道)

    扩展一个管道需要:

     1.编写功能函数

     2.把功能函数放到可引用的地方

     3.用新管道覆盖默认的管道

    写功能时比较简单,但是需要注意的是,管道功能的排列顺序会影响到认证流程,因此需要谨慎安排。pipeline的位置会决定每个管道会收到什么参数,比如,把你自定义的功能管道放到social_core.pipeline.user.create_user可以确保你的功能得到一个用户实例(创建的或者是已经存在的)而不是None。pipeline管道功能函数会收到需要参数,包含使用的后端,不同的模型实例,服务器request和社交提供商的response,简单介绍如下:

    strategy:当前strategy实例

    backend:当前backend实例

    uid:社交服务商提供的uid,这个uid是当前用户在社交服务商处的唯一标识。

    response:{}或者object()

     服务器user-details response,取决于使用的协议(),通常是一个包含用户个人信息详情的dict,这已经包含了许多的用户详情,有时scope会增加信息的总量


    details = {}
    后端产生的用户的基本信息,用来去创建或者更新user model(字典中包含username,email.first_name,last_name 和fullname等值)

    user = None
    user实例,如果没有创建用户或者在数据库中没有找到则是None
    social = None
    给出用户已关联的社交认证,如果用户没有创建或者数据库中不存在则返回None

    通常自定义管道功能函数时,只需要从response中获得一些参数,但是你可以通过调用其他api去获取更多用户信息,然后存储到其他地方。

    下面是一个创建用户Profile实例的一个例子,profile实例存储的是一些社交服务商返回的信息,(如Facebook,Facebook的response通常如下)

    {
        'username': 'foobar',
        'access_token': 'CAAD...',
        'first_name': 'Foo',
        'last_name': 'Bar',
        'verified': True,
        'name': 'Foo Bar',
        'locale': 'en_US',
        'gender': 'male',
        'expires': '5183999',
        'email': 'foo@bar.com',
        'updated_time': '2014-01-14T15:58:35+0000',
        'link': 'https://www.facebook.com/foobar',
        'timezone': -3,
        'id': '100000126636010',
    }

    假如我们想存储用户的个人简介链接,性别和时区到数据库,则功能管道可以如下:

    def save_profile(backend, user, response, *args, **kwargs):
        if backend.name == 'facebook':
            profile = user.get_profile()
            if profile is None:
                profile = Profile(user_id=user.id)
            profile.gender = response.get('gender')
            profile.link = response.get('link')
            profile.timezone = response.get('timezone')
            profile.save()

    现在我们只需要让soical-auth使用我们的管道即可,因为这个管道需要user实例,我们需要把他放到social_core.pipeline.user.create_user之后,可以确保有一个用户。

    SOCIAL_AUTH_PIPELINE = (
        'social_core.pipeline.social_auth.social_details',
        'social_core.pipeline.social_auth.social_uid',
        'social_core.pipeline.social_auth.auth_allowed',
        'social_core.pipeline.social_auth.social_user',
        'social_core.pipeline.user.get_username',
        'social_core.pipeline.user.create_user',
        'path.to.save_profile',  # <--- set the path to the function
        'social_core.pipeline.social_auth.associate_user',
        'social_core.pipeline.social_auth.load_extra_data',
        'social_core.pipeline.user.user_details',
    )

    目前我们创建的管道功能函数返回时None,即被看做返回的是{},如果你想要profile能在下个管道中使用,那你只需要返回{'profile':profile}.



    六、异常处理

    在认证过程中会产生许多异常,需要处理,此时可以利用django Middleware来解决。

    django social auth提供了一个基础中间件,通过Django消息框架向用户提供消息,然后通过重定向到一个中间件方法中定义的URL来处理SocialAuthBaseException。

    中间件在social_django.middleware.SocialAuthExceptionMiddleware。 其中的任何方法都可以被覆盖,但为了简单起见,建议使用这两种方法:

    get_message(request, exception)
    get_redirect_uri(request, exception)
    

    默认情况下,消息是异常消息,重定向的URL是由LOGIN_ERROR_URL设置指定的位置。

    如果'strategy()'装饰器检测到有效的后端,则它将在request.strategy.backend中可用,并且process_exception()将使用它来构建后端相关的重定向URL,但如果未定义,则将其回退到默认值。

    如果下列设置中,任意一项被定义为True,那么异常处理都是不能够使用:

    <backend name>_SOCIAL_AUTH_RAISE_EXCEPTIONS = True
    SOCIAL_AUTH_RAISE_EXCEPTIONS = True
    RAISE_EXCEPTIONS = True
    DEBUG = True
    

    重定向的目的会得到两个参数:

    message = ''
    来自触发异常处的消息,在某些情况下,它是在验证过程中由社交运营商返回的消息
    Message from the exception raised, in some cases it’s the message returnedby the provider during the auth process.
    backend = ''
    正在使用的后端(backend),前提是合法的后端

    中间件将尝试使用Django内置消息应用程序来存储异常消息,并使用社会认证和后端名称进行标记。 如果应用程序未启用或发生MessageFailure错误,则应用程序将默认为上述URLformat。


  • 相关阅读:
    linux 安装mysql及配置
    django restframework的应用
    python uuid的连接及简单应用
    Flink开发-Flink的计算模型和接口
    数据仓库-基本框架和内容
    数据仓库-需求沟通和开发示例
    Spark开发-开发总览
    Hive 高阶应用开发示例(二)
    Hive 高阶应用开发示例(一)
    Spark开发-关联分析
  • 原文地址:https://www.cnblogs.com/hiveme/p/8194828.html
Copyright © 2020-2023  润新知