一、开发环境
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-django2.在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数据根据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.用新管道覆盖默认的管道
strategy:当前strategy实例
backend:当前backend实例
uid:社交服务商提供的uid,这个uid是当前用户在社交服务商处的唯一标识。
response:{}或者object()
服务器user-details response,取决于使用的协议(),通常是一个包含用户个人信息详情的dict,这已经包含了许多的用户详情,有时scope会增加信息的总量
-
-
后端产生的用户的基本信息,用来去创建或者更新user model(字典中包含username,email.first_name,last_name 和fullname等值)
-
- user实例,如果没有创建用户或者在数据库中没有找到则是None
- 给出用户已关联的社交认证,如果用户没有创建或者数据库中不存在则返回None
details = {}
user = None
social = 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 from the exception raised, in some cases it’s the message returnedby the provider during the auth process.
- 正在使用的后端(backend),前提是合法的后端
message = ''
backend = ''
中间件将尝试使用Django内置消息应用程序来存储异常消息,并使用社会认证和后端名称进行标记。 如果应用程序未启用或发生MessageFailure错误,则应用程序将默认为上述URLformat。