QQ登录功能开发流程如下图:

第1步、QQ互联注册网站应用
打开QQ互联,进入管理中心。注册一下应用开发者,并添加网站应用,获得对应的appid与appkey。

申请appid和appkey的用途
appid:应用的唯一标识。在OAuth2.0认证过程中,appid的值即为oauth_consumer_key的值。
appkey:appid对应的密钥,访问用户资源时用来验证应用的合法性。在OAuth2.0认证过程中,appkey的值即为oauth_consumer_secret的值。

理解回调地址需要了解一下OAuth协议。
在你的网站页面里面,打开授权页面(这个授权页面不是回调地址)。在授权页面里面,登录QQ并确认授权。
授权之后,会得到一个授权码。回调地址就是用于接收这个授权码。
授权码以GET的方式返回,例如 http://www.junxi.site/web/oau...
通过这种方式,可以获取授权码,所以需要提供一个地址。这个地址先写一个暂时没有的地址,后面开发的时候,再给这个地址写对应的响应方法。

第2步、放置QQ按钮

这个QQ按钮是提供QQ登录的入口。从腾讯提供的QQ按钮下载放到你的登录页面即可。

不用看帮助文档里面的什么前端代码。这些用不上,只需要加一个固定的访问链接,再重定向即可。
前端页面此处的代码如下:

<div><span>其他登录方式:</span><a href="{% url 'qq_login' %}">![](/static/images/connect_qq.png)</a>
</div>

qq_login链接在下面第3步创建web应用里面设置。

第3步、创建web应用

怎么创建应用就不细说了,这是基本功。这里我已经创建了一个名称为web的django app应用。
创建完成之后,打开models.py文件,编写模型:

#!/usr/bin/env python
# _*_ coding:utf-8 _*_
__author__ = 'junxi'import sys
reload(sys)
sys.setdefaultencoding('utf8')class OAuthQQ(models.Model):"""QQ and User Bind"""user = models.ForeignKey(UserProfile)   # 关联用户信息表qq_openid = models.CharField(max_length=64)   # QQ的关联OpenID# def __str__(self):#    return self.user

该模型用于存储QQ登录返回的OpenID值。这个OpenID值是用QQ号一一对应。腾讯不给得到真实QQ号可能是出于保护隐私的考虑。

在总的urls路由中,加入这个应用路由。(总路由在和工程名一样的文件夹中的urls.py文件。这种方式对urls管理比较清晰)

from django.conf.urls import url, include
from django.contrib import admin
import web.urls
import web.viewsurlpatterns = [url(r'^admin/', admin.site.urls),url(r'^web/', include(web.urls)),
]

路由控制根据自己的工程自己写即可。

打开web应用目录下urls.py文件,先写一下需要哪些链接地址:

from django.conf.urls import url
from .views import *urlpatterns = [url(r'^oauth/qq/login/$', login, name='qq_login'),url(r'^oauth/qq/check/$', login, name='qq_check'),url(r'^oauth/bind/account/$', login, name='bind_account'),
]

qq_login和qq_check,分别是打开授权页面和回调地址。
bind_account是绑定用户的页面。
大致思路是授权之后,得到OpenID。判断这个OpenID是否存在数据库中。若存在,则直接登录对应的用户即可;若不存在,则打开这个绑定邮箱页面,绑定对应的用户。

第4步、开发OAuth登录功能

为了管理好OAuth,在web应用的文件夹下创建oauth_client.py文件。把相关的OAuth操作方法集成在一起。编辑oauth_client.py文件:

#!/usr/bin/env python
# _*_ coding:utf-8 _*_
__author__ = 'junxi'import json
import urllib, urllib2, urlparseclass OAuthQQ:def __init__(self, client_id, client_key, redirect_uri):self.client_id = client_idself.client_key = client_keyself.redirect_uri = redirect_uridef get_auth_url(self):"""获取授权页面的网址"""params = {'client_id': self.client_id,'response_type': 'code','redirect_uri': self.redirect_uri,'scope': 'get_user_info','state': 1}url = 'https://graph.qq.com/oauth2.0/authorize?%s' % urllib.urlencode(params)return url

创建一个类,需要申请QQ登录的APP_ID、APP_KEY和回调地址。这些都是固定的,我把这几个常量放入到settings.py中。settings.py添加如下常量,具体的值请在你的申请页面查找(这里还需要提一下,本地调试的方法。因为授权之后是调整到部署之后的网站上,而部署的网站还没开发响应的代码,无法响应对应的地址。这里我是本地测试环境,强制绑定Hosts域名文件解析):

# OAuth设置
QQ_APP_ID = 'XXXXXX'
QQ_KEY = 'XXXXXX'
QQ_RECALL_URL = 'http://www.junxi.site/web/oauth/qq/check'

回到OAuthQQ类,现里面有个get_auth_url方法。该方法是获取打开授权页面的链接地址。(可参考官方帮助,写得不够清晰)

接着,在编辑web应用的views.py文件,加入qq_login对应的响应方法:

from django.shortcuts import HttpResponseRedirect
from django.conf import settings
from oauth_client import OAuthQQdef qq_login(request):oauth_qq = OAuthQQ(settings.QQ_APP_ID, settings.QQ_KEY, settings.QQ_RECALL_URL)#获取 得到Authorization Code的地址url = oauth_qq.get_auth_url()#重定向到授权页面return HttpResponseRedirect(url)

到这里为止,就完成了点击QQ登录按钮,跳转到授权页面。
登录授权之后,授权页面会自动跳转到我们设置的回调地址。例如 http://www.junxi.site/web/oau...
我们可以获取这个地址上面的GET参数。先假设我们可以顺利获取到,继续完善OAuthQQ类。拿到这个授权码之后,需要用该码获取腾讯的access_token通行令牌。

打开oauth_client.py文件,在OAuthQQ类添加如下方法:

    def get_access_token(self, code):"""根据code获取access_token"""params = {'grant_type': 'authorization_code','client_id': self.client_id,'client_secret': self.client_key,'code': code,'redirect_uri': self.redirect_uri}    # 回调地址url = 'https://graph.qq.com/oauth2.0/token?%s' % urllib.urlencode(params)# 访问该网址,获取access_tokenresponse = urllib2.urlopen(url).read()result = urlparse.parse_qs(response, True)access_token = str(result['access_token'][0])self.access_token = access_tokenreturn access_token

该方法使用了urllib2,在服务器后台访问对应的链接,获取access_token,并返回该值。因为我后续不需要用access_token做其他动作,直接一次性获取QQ昵称和OpenID。所以不用记录这个通行令牌的有效期。

得到这个access_token之后,就可以做其他事了。首先需要获取授权用户的OpenID,因为腾讯不允许获取QQ号。只好退而求次,获取并保存OpenID。可参考官方文档。
继续给这个OAuthQQ添加获取OpenID的方法和使用OpenID获取QQ基本信息的方法:

    def get_open_id(self):"""获取QQ的OpenID"""params = {'access_token': self.access_token}url = 'https://graph.qq.com/oauth2.0/me?%s' % urllib.urlencode(params)response = urllib2.urlopen(url).read()v_str = str(response)[9:-3]  # 去掉callback的字符v_json = json.loads(v_str)openid = v_json['openid']self.openid = openidreturn openiddef get_qq_info(self):"""获取QQ用户的资料信息"""params = {'access_token': self.access_token,'oauth_consumer_key': self.client_id,'openid': self.openid}url = 'https://graph.qq.com/user/get_user_info?%s' % urllib.urlencode(params)response = urllib2.urlopen(url).read()return json.loads(response)

腾讯返回OpenID和QQ基本信息的内容格式都不一样。

再回头编辑views.py,添加回调地址的处理方法:

from django.shortcuts import render, HttpResponseRedirect, HttpResponse, reverse # reverse url逆向解析
from django.http import JsonResponse
from . import models
from .form import *
import json
import time
from django.conf import settings
from oauth_client import OAuthQQdef qq_check(request):  # 第三方QQ登录,回调函数"""登录之后,会跳转到这里。需要判断code和state"""request_code = request.GET.get('code')oauth_qq = OAuthQQ(settings.QQ_APP_ID, settings.QQ_KEY, settings.QQ_RECALL_URL)# 获取access_tokenaccess_token = oauth_qq.get_access_token(request_code)time.sleep(0.05)  # 稍微休息一下,避免发送urlopen的10060错误open_id = oauth_qq.get_open_id()print open_id# 检查open_id是否存在qq_open_id = models.OAuthQQ.objects.filter(qq_openid=str(open_id))print qq_open_idif qq_open_id:# 存在则获取对应的用户,并登录user = qq_open_id[0].user.usernameprint userrequest.session['username'] = userreturn HttpResponseRedirect('/web/')else:# 不存在,则跳转到绑定用户页面infos = oauth_qq.get_qq_info()  # 获取用户信息url = '%s?open_id=%s&nickname=%s' % (reverse('bind_account'), open_id, infos['nickname'])return HttpResponseRedirect(url)

按照思路,授权之后,调整到处理授权结果的页面。获取授权码之后,用get_access_token方法得到access_token。
再用access_token获取OpenID。坑出现了,若不加time.sleep(0.05)休息一下的话,会得到urlopen 10060错误。
获取到open_id之后,再判断一下数据库中是否存在。若存在,则已经关联对应的用户了,直接登录该用户。
若open_id不存在,则跳转到绑定用户的页面。该页面需要知道open_id和QQ昵称(为什么需要QQ昵称,下一步会提到)。通过GET方式,把这两个参数写在链接上即可传递过去。

第5步、绑定用户

上面提到若open_id在数据库中不存在,则打开绑定用户页面。该页面我设计成html表单,在templates下新建qq-bind-account.html文件。如下代码:

{% extends 'base.html' %}{% block title %}<title>QQ和账户绑定</title>
{% endblock %}{% block head-js %}
{% endblock %}{% block nav %}
{% endblock %}{% block content %}
<form class="form-horizontal" enctype="multipart/form-data" action="" method="post"><div class="login"><h1><a href="{% url 'index' %}">Primumest</a></h1><div class="login-bottom"><h2>HI,![](/static/images/connect_qq.png){{ nickname }}!您已登录。请绑定用户,完成QQ登录。</h2><div class="col-md-6"><div class="login-mail"><input type="text" placeholder="请输入你的账户名" name="username" required=""><i class="fa fa-user"></i></div><div class="login-mail"><input type="text" placeholder="请输入你的昵称" name="nickname" required=""><i class="fa fa-users"></i></div><div class="login-mail"><input type="password" placeholder="请输入密码" name="password" required=""><i class="fa fa-lock"></i></div><div class="login-mail"><input type="password" placeholder="请再次输入密码" name="password" required=""><i class="fa fa-lock"></i></div></div><div class="col-md-6 login-do"><label class="hvr-shutter-in-horizontal login-sub"><input type="submit" value="确定"></label></div><div class="clearfix"></div></div></div>
</form><!----><div class="copy-right"><p>© 2017 JunXi. All Rights Reserved</p></div>
{% endblock %}

接着,在views.py继续编辑,添加表单处理的对应方法:

def bind_account(request):  # 绑定账户open_id = request.GET.get('open_id')nickname = request.GET.get('nickname')if request.method == 'POST' and request.POST:data = request.POST # 接收到前台form表单传过来的注册账户信息user = models.UserProfile()username = data['username']password = data['password'].split(',')[0]user.username = usernamepassword = hash_sha256(password, username)user.password = passworduser.nickname = data['nickname']user.departments_id = 1user.save()oauthqq = models.OAuthQQ()oauthqq.qq_openid = open_idoauthqq.user_id = models.UserProfile.objects.get(username=username).idoauthqq.save()response = HttpResponseRedirect("/web/")request.session['username'] = username  # 设置sessionreturn response  # 返回首页return render(request, 'qq-bind-account.html', locals())

写完代码之后,本地测试可以通过。最后再部署到服务器并在QQ互联提交审核。一般审核要1~2天左右。若审核不通过,又不明白审核说明,就直接找客服问问。

urls.py

urlpatterns = [url(r'^oauth/qq/login', qq_login, name='qq_login'),url(r'^oauth/qq/check', qq_check, name='qq_check'),url(r'^oauth/bind/account', bind_account, name='bind_account'),
]

views.py

#!/usr/bin/env python
# _*_ coding:utf-8 _*_
__author__ = 'junxi'from django.shortcuts import render, HttpResponseRedirect, HttpResponse, reverse # reverse url逆向解析
from django.http import JsonResponse
from . import models
from .form import *
from script.salt_api import salt
from script.web_ssh import webssh
from django.contrib.auth.hashers import make_password, check_password
# from django.forms.models import model_to_dict
from django.core import serializers
import datetime
import json
import hashlib
import re
import time
import os
from django.conf import settings
from oauth_client import OAuthQQdef hash_sha256(password, username):  # sha256加密sha256 = hashlib.sha256()sha256.update((password + username).encode('utf-8'))sha256_password = sha256.hexdigest()return sha256_passworddef qq_login(request):  # 第三方QQ登录oauth_qq = OAuthQQ(settings.QQ_APP_ID, settings.QQ_KEY, settings.QQ_RECALL_URL)# 获取 得到Authorization Code的地址url = oauth_qq.get_auth_url()# 重定向到授权页面return HttpResponseRedirect(url)def qq_check(request):  # 第三方QQ登录,回调函数"""登录之后,会跳转到这里。需要判断code和state"""request_code = request.GET.get('code')oauth_qq = OAuthQQ(settings.QQ_APP_ID, settings.QQ_KEY, settings.QQ_RECALL_URL)# 获取access_tokenaccess_token = oauth_qq.get_access_token(request_code)time.sleep(0.05)  # 稍微休息一下,避免发送urlopen的10060错误open_id = oauth_qq.get_open_id()print open_id# 检查open_id是否存在qq_open_id = models.OAuthQQ.objects.filter(qq_openid=str(open_id))print qq_open_idif qq_open_id:# 存在则获取对应的用户,并登录user = qq_open_id[0].user.usernameprint userrequest.session['username'] = userreturn HttpResponseRedirect('/web/')else:# 不存在,则跳转到绑定用户页面infos = oauth_qq.get_qq_info()  # 获取用户信息url = '%s?open_id=%s&nickname=%s' % (reverse('bind_account'), open_id, infos['nickname'])return HttpResponseRedirect(url)def bind_account(request):  # 绑定账户open_id = request.GET.get('open_id')nickname = request.GET.get('nickname')if request.method == 'POST' and request.POST:data = request.POST # 接收到前台form表单传过来的注册账户信息user = models.UserProfile()username = data['username']password = data['password'].split(',')[0]user.username = usernamepassword = hash_sha256(password, username)user.password = passworduser.nickname = data['nickname']user.departments_id = 1user.save()oauthqq = models.OAuthQQ()oauthqq.qq_openid = open_idoauthqq.user_id = models.UserProfile.objects.get(username=username).idoauthqq.save()response = HttpResponseRedirect("/web/")request.session['username'] = username  # 设置sessionreturn response  # 返回首页return render(request, 'qq-bind-account.html', locals())

oauth_client.py

#!/usr/bin/env python
# _*_ coding:utf-8 _*_
__author__ = 'junxi'import json
import urllib, urllib2, urlparseclass OAuthQQ:def __init__(self, client_id, client_key, redirect_uri):self.client_id = client_idself.client_key = client_keyself.redirect_uri = redirect_uridef get_auth_url(self):"""获取授权页面的网址"""params = {'client_id': self.client_id,'response_type': 'code','redirect_uri': self.redirect_uri,'scope': 'get_user_info','state': 1}url = 'https://graph.qq.com/oauth2.0/authorize?%s' % urllib.urlencode(params)return urldef get_access_token(self, code):"""根据code获取access_token"""params = {'grant_type': 'authorization_code','client_id': self.client_id,'client_secret': self.client_key,'code': code,'redirect_uri': self.redirect_uri}    # 回调地址url = 'https://graph.qq.com/oauth2.0/token?%s' % urllib.urlencode(params)# 访问该网址,获取access_tokenresponse = urllib2.urlopen(url).read()result = urlparse.parse_qs(response, True)access_token = str(result['access_token'][0])self.access_token = access_tokenreturn access_tokendef get_open_id(self):"""获取QQ的OpenID"""params = {'access_token': self.access_token}url = 'https://graph.qq.com/oauth2.0/me?%s' % urllib.urlencode(params)response = urllib2.urlopen(url).read()v_str = str(response)[9:-3]  # 去掉callback的字符v_json = json.loads(v_str)openid = v_json['openid']self.openid = openidreturn openiddef get_qq_info(self):"""获取QQ用户的资料信息"""params = {'access_token': self.access_token,'oauth_consumer_key': self.client_id,'openid': self.openid}url = 'https://graph.qq.com/user/get_user_info?%s' % urllib.urlencode(params)response = urllib2.urlopen(url).read()return json.loads(response)

python 第三方插件登陆——QQ相关推荐

  1. python自动登录qq邮箱_selenium+python实现自动登陆QQ邮箱并发送邮件功能

    本期做一个selenium详细实例,会把我在元素定位中遇到的一些阻塞和经验分享给大家. (浏览器为Chrome) (如果只需要最终的完整代码,请直接跳转到文章最后) 浏览器打开QQ邮箱登录网址 fro ...

  2. python基础编程:selenium+python实现自动登陆QQ邮箱并发送邮件功能

    本期做一个selenium详细实例,会把我在元素定位中遇到的一些阻塞和经验分享给大家. (浏览器为Chrome) (如果只需要最终的完整代码,请直接跳转到文章最后) 浏览器打开QQ邮箱登录网址 QQ邮 ...

  3. python第三方插件pip是什么_Python怎么安装第三方模块?

    原标题:Python怎么安装第三方模块? Python中有哪几种方法安装第三方模块,安装Python第三方模块的方法有很多,这里介绍三种方法安装第三方模块. [方法一]: 通过setuptools来安 ...

  4. python第三方插件pip是什么_什么是pip,如何安装管理第三方模块

    什么是pip,如何安装管理第三方模块 pip 是python标准库的管理工具,使用它可以安装管理第三方库,本篇教程一篇新手引导教程,通过本篇教程,你可以学会掌握以下几点技能 安装第三方库 在 Pyth ...

  5. selenium+python实现自动登陆QQ邮箱,并发送邮件

    这里写自定义目录标题 selenium+pycharm实战,登录QQ邮箱,并发送邮件 浏览器打开QQ邮箱登录网址 元素定位,输入QQ账号和QQ密码 元素定位,写信界面 元素定位,邮件发送 元素定位总结 ...

  6. python第三方插件登录网易音乐_项目实战 | Python开发网易云音乐插件

    介绍 深度音乐播放器的网易云音乐插件,可在Linux下播放用户创建.收藏的歌单,以及私人FM. 1.基于sumary的dmusic-plugin-baidumusic修改而成 2.使用了NetEase ...

  7. python利用selenium登陆qq邮箱

    最开始自己写的代码: from selenium import webdriver browser=webdriver.Firefox() browser.get('https://mail.qq.c ...

  8. python第三方插件登录网易音乐_GitHub - TomoToTomoT/NeteaseCloudMusic-Python: 网易云音乐--python Api...

    #NeteaseCloudMusic-python 网易云音乐python版Api 开发文档 获取最新评论 req_comments(music_id, page = 1, page_num = 20 ...

  9. python第三方插件登录网易音乐_python3-使用requests模拟登录网易云音乐

    # -*- coding: utf-8 -*- from Crypto.Cipher import AES import base64 import random import codecs impo ...

最新文章

  1. 怎样用matlab打开mw文,C# matlab混合编程 MWArray使用笔记
  2. 听声辨位过时了!这个AI系统仅凭光回声就能得到3D图像
  3. Error:Execution failed for task ':myapp:dexDebug'. com.android.ide.common.process.ProcessExcepti
  4. 算法-有向环和拓扑排序
  5. 虚拟币交易平台开发_虚拟币软件开发未来发展的趋势怎么样?
  6. 博通1300亿美元收购高通,一场充满大饼和落井下石的“大戏”
  7. nginx.conf配置详解
  8. xyCMS框架的webshell
  9. iOS定时器-- NSTimer 和CADisplaylink
  10. 人脸检测算法_腾讯已开源高精度人脸检测算法DSFD
  11. Python补充之函数
  12. 交互设计实用指南系列(8)—深广度平衡
  13. python快速整理excel_python批量处理excel文件数据
  14. 有人一起用沙雕情侣头像吗?
  15. 物联网环境下信息安全问题与对策
  16. uboot中展示gpio接口的驱动
  17. openEuler-risc-v学习笔记
  18. audio的自动播放
  19. 2014新浪校招笔试题:取水果(17年第一篇让人懵逼的面试题)
  20. 【论文阅读】Feature Denoising for Improving Adversarial Robustness

热门文章

  1. diy无感无刷电机霍尔安装_无刷直流电机霍尔传感器安装方法研究
  2. 湖仓一体电商项目(一):项目背景和架构介绍
  3. 【笔记】STM32F4xx 时钟定时器
  4. 叩响港交所大门,KK集团能否成为“中国版秋叶原”?
  5. 基于stm32的MAX31865铂电阻PT100测温全套资料
  6. 用javascript统计字数,中文计数问题
  7. 计算机 显卡 淘汰,早该淘汰的VGA模拟接口:新显卡不再支持
  8. crontab: error renaming解决方法
  9. Vue使用快速使用Echarts图标以及使用水滴图
  10. 火山PC(火山视窗)图形按钮制作器教程