准备工作_OAuth2.0

接入QQ登录前,网站需首先进行申请,获得对应的appid与appkey,以保证后续流程中可正确对网站与用户进行验证与授权。

在开发的过程中,发现获取不到QQ号,只能获取一个OpenID的东西。最后采取存储这个OpenID并绑定对应账号的方式。

所以需要创建对应的模型,即创建一个应用管理第三方登录。

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按钮下载放到你的登录页面即可。

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

前端页面此处的代码如下:

其他登录方式:

![](/static/images/connect_qq.png)

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.views

urlpatterns = [

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, urlparse

class OAuthQQ:

def __init__(self, client_id, client_key, redirect_uri):

self.client_id = client_id

self.client_key = client_key

self.redirect_uri = redirect_uri

def 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 OAuthQQ

def 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_token

response = urllib2.urlopen(url).read()

result = urlparse.parse_qs(response, True)

access_token = str(result['access_token'][0])

self.access_token = access_token

return 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 = openid

return openid

def 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 OAuthQQ

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_token

access_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_id

if qq_open_id:

# 存在则获取对应的用户,并登录

user = qq_open_id[0].user.username

print user

request.session['username'] = user

return 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 %}

QQ和账户绑定

{% endblock %}

{% block head-js %}

{% endblock %}

{% block nav %}

{% endblock %}

{% block content %}

Primumest

HI,![](/static/images/connect_qq.png){{ nickname }}!您已登录。请绑定用户,完成QQ登录。

© 2017 JunXi. All Rights Reserved

{% 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 = username

password = hash_sha256(password, username)

user.password = password

user.nickname = data['nickname']

user.departments_id = 1

user.save()

oauthqq = models.OAuthQQ()

oauthqq.qq_openid = open_id

oauthqq.user_id = models.UserProfile.objects.get(username=username).id

oauthqq.save()

response = HttpResponseRedirect("/web/")

request.session['username'] = username # 设置session

return response # 返回首页

return render(request, 'qq-bind-account.html', locals())

访问测试:

打开首页

点击QQ登录

获取授权并登录

写完代码之后,本地测试可以通过。最后再部署到服务器并在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 OAuthQQ

def hash_sha256(password, username): # sha256加密

sha256 = hashlib.sha256()

sha256.update((password + username).encode('utf-8'))

sha256_password = sha256.hexdigest()

return sha256_password

def 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_token

access_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_id

if qq_open_id:

# 存在则获取对应的用户,并登录

user = qq_open_id[0].user.username

print user

request.session['username'] = user

return 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 = username

password = hash_sha256(password, username)

user.password = password

user.nickname = data['nickname']

user.departments_id = 1

user.save()

oauthqq = models.OAuthQQ()

oauthqq.qq_openid = open_id

oauthqq.user_id = models.UserProfile.objects.get(username=username).id

oauthqq.save()

response = HttpResponseRedirect("/web/")

request.session['username'] = username # 设置session

return 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, urlparse

class OAuthQQ:

def __init__(self, client_id, client_key, redirect_uri):

self.client_id = client_id

self.client_key = client_key

self.redirect_uri = redirect_uri

def 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

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_token

response = urllib2.urlopen(url).read()

result = urlparse.parse_qs(response, True)

access_token = str(result['access_token'][0])

self.access_token = access_token

return access_token

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 = openid

return openid

def 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互联_Django增加QQ第三方登录相关推荐

  1. python调用qq互联_Django项目中实现使用qq第三方登录功能

    使用qq登录的前提是已经在qq互联官网创建网站应用并获取到QQ互联中网站应用的APP ID和APP KEY 1,建路由 # qq登录 path('loginQq/',qq.loginQq,name=' ...

  2. PHP调用QQ互联接口实现QQ登录网站

    调用QQ登录接口,首先要到QQ互联完善开发者认证信息,并通过审核,然后创建一个网站应用,获得APP ID和APP Key,通过审核后即可调用基本接口get_user_info(获得用户信息),实现QQ ...

  3. Android中的友盟(微信、QQ、新浪)第三方登录分享

    前言:我再这里只总结Android开发人员需要做的,其他的就去看开发文档吧,例如获取Appkey,就找你的领导要去吧. 一.准备工作 第一步:快速集成. 快速集成包含自动集成与手动集成两种方式,开发者 ...

  4. QQ互联与财付通将打通登录态,移动支付更便捷

    随着移动互联网时代的迅猛发展,人类工作和生活方式发生了重大变化,从通讯到生活服务查询,再到线上购物,这一些以往要通过PC完成的动作,现在都只要一个手机就能解决,而支付便成为这个闭环中不可或缺的一个功能 ...

  5. qq互联android sdk,qq互联.Android

    导读:2.2调用示例,这里以发送文字微博接口的调用为例例,来说明通过requestAsync调用兼容接口的方法:,在上面的调用中,调用获取用户信息接口的示例代码如下:,调用发送带图微博接口的,http ...

  6. 解决 微信、QQ、微博、支付宝 第三方登录 不同应用间用户共享的问题

    背景:网页应用已运行很久,正在开发移动应用,需要进行用户共享(即同一个账号两边都可以登录),然后发现移动应用这边微信.QQ登录所获取到的openid和网页那边的不一样 微信 网页应用.移动应用分属不同 ...

  7. QQ互联第三方登录多应用用户登录打通

    2019独角兽企业重金招聘Python工程师标准>>> 在开发第三方登录的时候,发现qq互联的第三方登录openId在多个应用中用户登录无法打通,然后发送邮件咨询了一下qq互联(邮箱 ...

  8. 【第三方互联】3、腾讯QQ授权第三方登录

    当我们创建的 QQ 互联应用成功后,我们便可以开始使用该应用来实现 QQ 互联 一.获取 APP ID 和 APP Key 1.在 QQ 互联官网首页找到"我的应用" 2.点击应用 ...

  9. JavaWeb项目调用QQ登录----QQ互联

    首先要做的在QQ互联申请项目QQ互联官网首页 ,申请通过会得到APPID , APPKey  一 : 在HTML/JSP页面放置符合QQ互联标准的QQ登录图标 附代码: <a href=&quo ...

  10. java判断用户是否在某一个区域登录_Java实现QQ登录和微博第三方登录

    来源:http://www.cnblogs.com/liuxianan转自公众号:Java后端 1. 前言 个人网站最近增加了评论功能,为了方便用户不用注册就可以评论,对接了 QQ 和微博这 2 大常 ...

最新文章

  1. 甩开镣铐的精神舞蹈:推荐长篇小说《炼狱之花》
  2. 知道经纬度坐标怎么计算两点间距离_【我的时间拣屎】亚里士多德:地球是圆的,我计算了地球的圆周...
  3. SQL SERVER2008 存储过程、表、视图、函数的权限
  4. jsp页面的相关复习
  5. C++ 抛出和接收异常的顺序
  6. ESLint检测JavaScript代码
  7. 通过jQuery设置全局Ajax加载时呈现Loading
  8. mysql innodb 分区_MySQL 表分区详解MyiSam引擎和InnoDb 区别(实测)
  9. 文本文件与二进制的区别
  10. (工具)政企版WPS-没广告弹窗超简洁
  11. 天空之城 matlab,matlab演奏《天空之城》代码
  12. 练习7-9 计算天数(15 分)
  13. 小米手机系统服务组件是干什么的_2799 元!小米 1 亿像素拍照手机来了,还有 MIUI 系统的小米手表...
  14. [SPRD]展锐Android R关机充电动画修改
  15. 微命令、微操作、微指令、微程序
  16. 技术人从职场中脱颖而出的成长秘诀
  17. Caused by: io.netty.resolver.dns.DnsNameResolverTimeoutException: [/192.168.1.1:53] query via UDP ti
  18. POJ 2142-The Balance(扩展欧几里德)
  19. Linux命令:使用dig命令解析域名
  20. php windows环境安装(图文版)

热门文章

  1. 蓝桥杯2022年第十三届决赛真题-迷宫
  2. threejs 三面体_Three.js基础探寻五——正二十面体、圆环面等
  3. (vivo)安卓神器xposed框架Root安装指南
  4. 天正电气图例_天正电气CAD教程之文件布图篇(内附往期秘籍)
  5. 【Linux实验】Linux操作基础
  6. Multitask Learning
  7. json转xml、xml转json
  8. amazeui学习笔记--js插件(UI增强)--警告框Alert
  9. 十大著名黑客-----凯文-米特尼克
  10. MySQL运算符介绍(萌新必备!!)