我的网站搭建(第32天) OAuth功能整合

  • 发布时间:2016年10月17日 11:32
  • 作者:杨仕航
* 该文是基于Python2.7开发的,最新Python3.x和Django2.x视频教程可以前往 >> Django2.0视频教程

前面写了3篇有个OAuth第三方登录的博文:QQ第三方登录新浪微博第三方登录Github第三方登录

由于一开始没有整体的构架,导致写了这几个第三方账号登录之后,代码有很多重复且冗余。

所以对这部分功能进行整理并优化。


有一点需要说明,本篇博文不涉及具体OAuth实现的代码,着重讲功能整合和结构性的东西。

具体实现OAuth代码和这3个第三方账号的OAuth申请可以参考上面3篇博文。

源码我也放在Github上:https://github.com/HaddyYang/django-oauth


至于都OAuth还不太理解的小伙伴们,看下图:

实际上,OAuth相当于第三方账号网站提供的接口,需要先认证,拿到通行令牌access_token,才能继续调用接口获取数据。有不少人卡在这个地方。看上图再理解一下,准备进入正题。


通过之前3篇博文说是3个第三方网站OAuth开发之后,发现设置的内容基本一致。若把设置的数据放在settings.py文件会导致不方便维护,所以我考虑把这些设置放在数据库中。则需要创建模型,打开OAuth的models.py文件:

#coding:utf-8
from django.db import models

#若不是使用系统的用户认证,可以换成你自己的用户系统
from django.contrib.auth.models import User 

class OAuth_type(models.Model):
    """OAuth类型"""
    type_name = models.CharField(max_length = 12)
    title = models.CharField(max_length = 12)
    #图片上传的路径可以修改成自己的
    img = models.FileField(upload_to='static/img/connect') 

    #oauth基本设置
    client_id = models.CharField(max_length = 24, default='')
    client_secret = models.CharField(max_length = 48, default='')
    redirect_uri = models.URLField(default='')
    scope = models.CharField(max_length = 24, default='')

    #oauth请求链接
    url_authorize = models.URLField(default='', blank=True)
    url_access_token = models.URLField(default='', blank=True)
    url_open_id = models.URLField(default='', blank=True)
    url_user_info = models.URLField(default='', blank=True)
    url_email = models.URLField(default='', blank=True)

    def __unicode__(self):
        return self.type_name

class OAuth_ex(models.Model):
    """User用户绑定"""
    user = models.ForeignKey(User)   #和User关联的外键
    openid = models.CharField(max_length = 64) 
    oauth_type = models.ForeignKey(OAuth_type, default=1)  #关联账号的类型

    def __unicode__(self):
        return u'<%s>' % (self.user)

OAuth_type模型是保存OAuth相关设置,分为3部分:第1部分填写该类型相关的信息;第2部分填写基本的设置(例如密匙、回调地址等);第3部分填写相关数据请求链接。

OAuth_ex模型是保存第三方账号和自己网站用户关联信息。


由于OAuth要设置的内容比较多,在django后台管理中可以对其分组显示。打开OAuth的admin.py文件:

#coding:utf-8
from django.contrib import admin
from .models import OAuth_type, OAuth_ex

# Register your models here.
class OAuthTypeAdmin(admin.ModelAdmin):
    list_display=('id','type_name', 'title', 'img')

    #分组表单
    fieldsets = (
        (u'OAuth类型信息', {
            "fields":('type_name', 'title', 'img')
            }),
        (u'OAuth基本设置', {
            "fields":('client_id','client_secret','redirect_uri','scope')
            }),
        (u'OAuth请求链接', {
            "fields":('url_authorize','url_access_token','url_open_id','url_user_info','url_email')
            })
    )

class OAuthAdmin(admin.ModelAdmin):
    list_display=('id', 'user', 'openid','oauth_type')

admin.site.register(OAuth_ex, OAuthAdmin)
admin.site.register(OAuth_type, OAuthTypeAdmin)

效果如下图:



把OAuth设置信息放到模型中之后,发送认证信息到第三方网站的请求方法就可以统一写成1个方法(oauth的views.py文件):

#coding:utf-8
from django.http import Http404
from django.forms.models import model_to_dict #模型对象转字典

from .models import OAuth_ex, OAuth_type
from .oauth_client import OAuth_Base

def _get_oauth(type_name, state):
    """获取对应的OAuth对象"""
    try:
        oauth_type = OAuth_type.objects.get(type_name = type_name)
    except:
        raise Http404

    kw = model_to_dict(oauth_type)
    kw['state'] = state
    return OAuth_Base.Get_OAth(**kw)

此处,把模型转成dict字典,再调用oauth_client.py文件中的OAuth_Base基类静态方法获取对应的第三方账号登录处理对象。


至于oauth_client.py文件中的4个类:OAuth_Base是基类;OAuth_QQ、OAuth_Sina、OAuth_Github是继承了OAuth_Base类,实现具体的OAuth方法。若你要新增其他的第三方账号登录,可以参考这3个类。

总体流程如下图:

通过路由设置传递OAuth第三方账号类型,读取配置,选择对应的类。获取到已经写好的类之后,再利用得到的用户信息进一步处理。

到这里OAuth框架性的东西和整理的部分已经讲解完毕。(很多东西前面的博文已经讲解了)


但对于整个用户认证系统来说,只是完成一半的功能而已。还有一半的功能是绑定用户。这部分的代码根据自己的网站具体情况实现。每个网站的用户认证系统不太可能一样。

我的网站用户认证是采用Django自带的,并使用邮箱地址作为用户名。

所以在我分享的源码中可以找到form.py文件,此文件是绑定用户的表单。另外templates中的模版文件也是我网站使用到的。

form.html是通用表单;message.html是信息提示页面。

对应的代码我也封装了,具体可以参考我的源码:https://github.com/HaddyYang/django-oauth


上一篇:C#组合框数据源绑定类

下一篇:Access中ADO和DAO like查询的区别

评论列表

wongjyusing

wongjyusing

博主,我现在使用的是python3, urllib2用不了,我试过用urllib.request() 这有什么方法解决呢?

2018-07-13 21:30 回复

  • wongjyusing

    ⁣我试过用urllib.request() ,仍然不行,这有什么方法解决呢?

    2018-07-13 21:45 回复

新的评论

清空