我的网站搭建(第48天) OAuth登录自动获取头像

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

前面开发了QQ、新浪微博和Github第三方登录,即OAuth。上次又给用户添加了头像。

那么问题来了:如果从未在我网站注册用户,直接用OAuth第三方注册并登录之后没有头像。

用户还需要自己手动再设置头像。这点对用户来说有些麻烦,用户体验不是很好。

我们可以改进为:若用第三方社交账号登录,则使用该第三方账号的头像作为我网站该用户账号的头像。


1、OAuth相关文章

Django的OAuth相关文章前面有了,这里就不在赘述。有兴趣可以先看看这些文章。

我的网站搭建(第23天) 第三方登录:QQ

我的网站搭建(第28天) 第三方登录:新浪微博

我的网站搭建(第30天) 第三方登录:Github

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


2、用户头像相关文章

我使用的用户系统是Django自带的用户系统。Django的用户系统没有头像字段和功能,我对其相关做了一些拓展。文章如下:

我的网站搭建(第44天) 添加头像字段

我的网站搭建(第45天) 上传头像

我的网站搭建(第46天) 在线头像

我的网站搭建(第47天) 修改评论列表的样式(头像的使用)


3、判断用户是否设置了头像

为了避免重复设置头像,需要判断用户是否已经设置了头像。

同样使用给类动态绑定函数的方法,给User用户类绑定判断是否有头像的函数。(可见我的网站搭建(第44天) 添加头像字段

该方法可以大大简化代码结构。我给User拓展添加了一个User_Avatar模型,用于管理用户头像。

添加判断代码写在models.py文件中,如下所示:

#coding:utf-8
from django.db import models
from django.contrib.auth.models import User
from types import MethodType #类动态绑定方法

class User_Avatar(models.Model):
    """用户头像拓展模型"""
    user = models.ForeignKey(User)
    avatar = models.ImageField(upload_to=AVATAR_ROOT)
    
def has_avatar(self):
    """判断是否有设置头像"""
    return User_Avatar.objects.filter(user=self.id).count() > 0
    
#动态绑定方法
User.has_avatar = MethodType(has_avatar, None, User)

ps:前面的文章中,我还动态绑定当前用户头像和设置用户头像的方法。


4、OAuth登录获取头像

OAuth相关代码太多了,这个请看上面罗列的OAuth相关博文。

我还进一步对OAuth代码整理。这个我会在我的Django视频教程中详细讲解(课程还在录制中,没那么快)

不同的第三方账号获取头像的位置大致相同,都是获取账号用户信息。

在账号用户信息中就附带了头像链接。相应的API如下:

QQ的OAuth获取用户信息:http://wiki.open.qq.com/wiki/website/get_user_info

新浪的OAuth获取用户信息:http://open.weibo.com/wiki/2/users/show

Github的OAuth获取用户信息:https://developer.github.com/v3/users/


以QQ为例,在获取QQ用户信息返回数据如下:

20170320/20170320143254251.png

其中,我们可以使用figureurl_qq_1参数值获取一个40*40的头像。

获取头像代码如下:

#coding:utf-8
import os, re, json, time
import urllib, urllib2, urlparse
import uuid
from django.conf import settings

class OAuth_QQ(OAuth_Base):
    #还有其他相关代码,可参考前面写的OAuth相关博文
    user_info = {}
    
    #头像保存的临时目录
    temp_folder = os.path.join(settings.BASE_DIR, 'static', 'temp')
    
    def get_user_info(self):
        """获取QQ用户的资料信息"""
        if not self.user_info:
            params = {'access_token': self.access_token,
                      'oauth_consumer_key': self.client_id,
                      'openid': self.openid}
            response = self._get(self.url_user_info, params)
            self.user_info = json.loads(response)
        return self.user_info

    def download_avatar(self):
        """下载头像图片"""
        if not self.user_info:
            self.get_user_info()

        #获取头像链接 40*40
        url = self.user_info['figureurl_qq_1']
        filename = os.path.join(self.temp_folder, uuid.uuid1().hex + '.jpg')

        #下载头像图片
        urllib.urlretrieve(url, filename)
        return filename

这里,统一把头像下载到临时目录,并用uuid随机设置文件名。

而且不管下载头像是什么图片格式,统一写jpg格式。(不用担心待会裁剪图片格式问题,PIL读取图片格式会自动识别)


5、裁剪并应用图片

由于download下来的头像尺寸不一定是64*64,需要对头像进一步处理。

这里我也优化了前面博文写的裁剪图片代码,将该部分代码拆分出来。

def _cut_save_avatar(user, temp_path, left=0, top=0, width=0, height=0):
    #python2.7 pillow
    from PIL import Image
    im = Image.open(temp_path)

    #裁剪图片
    if width==0 or height==0:
        right, bottom = im.size
    else:
        right = left + width
        bottom = top + height
    crop_im = im.convert("RGBA").crop((left, top, right, bottom)).resize((64, 64), Image.ANTIALIAS)

    #设置背景颜色为白色
    out = Image.new('RGBA', crop_im.size, (255,255,255))
    out.paste(crop_im, (0, 0, 64, 64), crop_im)

    #保存图片
    out.save(temp_path)

    #保存记录
    avatar = user.set_avatar_url(temp_path)
    os.remove(temp_path)

    #返回头像路径
    return avatar.avatar.url


结合下载头像的代码,就可以实现OAuth登录并自动获取和应用头像功能。代码如下:

def _check_oauth_avatar(user, oauth):
    """OAuth登录,头像处理"""
    #判断头像是否存在
    if not user.has_avatar():
        try:
            temp_path = oauth.download_avatar() #获取并下载头像到本地
            _cut_save_avatar(user, temp_path)   #裁剪并保存头像
        except Exception as e:
            print(e.message)
    return True

只需要传递user对象和自己写的oauth对象即可。并在OAuth登录成功之后,执行一下该方法即可。

上一篇:Django的aggregate究竟是何方妖孽

下一篇:VSTO判断选中的对象是否是单元格

评论列表

智慧如你,不想发表一下意见吗?

新的评论

清空