Python的Flask框架应用程序实现使用QQ账号登录的方法


Posted in Python onJune 07, 2016

Flask-OAuthlib是OAuthlib的Flask扩展实现,
项目地址:
https://github.com/lepture/flask-oauthlib
主要特性:

  • 支持OAuth 1.0a, 1.0, 1.1, OAuth2客户端
  • 友好的API(和Flask-OAuth一样)
  • 与Flask直接整合
  • 等等……

Flask-OAuthlib提供了多个开放平台的示例代码,比如Google, Facebook, Twiter, Github, Dropbox, 豆瓣, 微博等,只是暂时没有QQ登录的示例代码。

QQ OAuth登录示例
下面是QQ登录的代码:

import os
import json
from flask import Flask, redirect, url_for, session, request, jsonify, Markup
from flask_oauthlib.client import OAuth

QQ_APP_ID = os.getenv('QQ_APP_ID', '101187283')
QQ_APP_KEY = os.getenv('QQ_APP_KEY', '993983549da49e384d03adfead8b2489')

app = Flask(__name__)
app.debug = True
app.secret_key = 'development'
oauth = OAuth(app)

qq = oauth.remote_app(
  'qq',
  consumer_key=QQ_APP_ID,
  consumer_secret=QQ_APP_KEY,
  base_url='https://graph.qq.com',
  request_token_url=None,
  request_token_params={'scope': 'get_user_info'},
  access_token_url='/oauth2.0/token',
  authorize_url='/oauth2.0/authorize',
)


def json_to_dict(x):
  '''OAuthResponse class can't not parse the JSON data with content-type
  text/html, so we need reload the JSON data manually'''
  if x.find('callback') > -1:
    pos_lb = x.find('{')
    pos_rb = x.find('}')
    x = x[pos_lb:pos_rb + 1]
  try:
    return json.loads(x, encoding='utf-8')
  except:
    return x


def update_qq_api_request_data(data={}):
  '''Update some required parameters for OAuth2.0 API calls'''
  defaults = {
    'openid': session.get('qq_openid'),
    'access_token': session.get('qq_token')[0],
    'oauth_consumer_key': QQ_APP_ID,
  }
  defaults.update(data)
  return defaults


@app.route('/')
def index():
  '''just for verify website owner here.'''
  return Markup('''<meta property="qc:admins" '''
         '''content="226526754150631611006375" />''')


@app.route('/user_info')
def get_user_info():
  if 'qq_token' in session:
    data = update_qq_api_request_data()
    resp = qq.get('/user/get_user_info', data=data)
    return jsonify(status=resp.status, data=resp.data)
  return redirect(url_for('login'))


@app.route('/login')
def login():
  return qq.authorize(callback=url_for('authorized', _external=True))


@app.route('/logout')
def logout():
  session.pop('qq_token', None)
  return redirect(url_for('get_user_info'))


@app.route('/login/authorized')
def authorized():
  resp = qq.authorized_response()
  if resp is None:
    return 'Access denied: reason=%s error=%s' % (
      request.args['error_reason'],
      request.args['error_description']
    )
  session['qq_token'] = (resp['access_token'], '')

  # Get openid via access_token, openid and access_token are needed for API calls
  resp = qq.get('/oauth2.0/me', {'access_token': session['qq_token'][0]})
  resp = json_to_dict(resp.data)
  if isinstance(resp, dict):
    session['qq_openid'] = resp.get('openid')

  return redirect(url_for('get_user_info'))


@qq.tokengetter
def get_qq_oauth_token():
  return session.get('qq_token')


if __name__ == '__main__':
  app.run()

主要流程:

  • 访问QQ互联网站 http://connect.qq.com/ 注册成为开发者,并申请应用,申请应用时需要验证网站所有权;
  • 应用申请好之后,把QQ_APP_ID和QQ_APP_KEY替换为你的应用的;
  • 访问/login,然后会跳转到QQ的授权验证网页;
  • QQ验证通过之后,会跳转回到/login/authorized,并获取access_token;
  • 得到access_token之后,通过access_token获取openid,access_token和openid是后期调用其它API的必要参数;
  • 跳转到/user_info,获取并显示登录用户的基本信息。

更多信息请参阅Flask-OAuthlib文档和QQ互联文档:

https://flask-oauthlib.readthedocs.org/
http://wiki.connect.qq.com/
关于SAE平台的特别说明
在SAE平台上,授权过程没有任何问题,当获取到access_token之后,调用API时,会在请求时(比如get, put)附加类似如下的请求头:

headers = {u'Authorization': u'Bearer 83F40E96FB6882686F4DF1E17105D04E'}

这个请求头会引发HTTPError: HTTP Error 400: Bad request,造成请求失败。解决的办法是把键名转换成str类型,Hack代码如下:

def convert_keys_to_string(dictionary):
  """Recursively converts dictionary keys to strings."""
  if not isinstance(dictionary, dict):
    return dictionary
  return dict((str(k), convert_keys_to_string(v))
    for k, v in dictionary.items())

def change_qq_header(uri, headers, body):
  headers = convert_keys_to_string(headers)
  return uri, headers, body

qq.pre_request = change_qq_header

当项目部署在SAE平台时,将这段代码放在if __name__ == '__main__'语句之前即可。

小结
OAuth2登录验证还是比较容易的,绝大多数的平台都支持标准的协议,使用通用的库可以简化开发流程。另外,QQ登录的代码已经提交到Flask-OAuthlib代码库了。

Python 相关文章推荐
linux系统使用python获取cpu信息脚本分享
Jan 15 Python
Python实现拼接多张图片的方法
Dec 01 Python
python操作gmail实例
Jan 14 Python
Python中实现三目运算的方法
Jun 21 Python
Django ORM框架的定时任务如何使用详解
Oct 19 Python
Python基于mysql实现学生管理系统
Feb 21 Python
Python生成六万个随机,唯一的8位数字和数字组成的随机字符串实例
Mar 03 Python
python opencv实现图片缺陷检测(讲解直方图以及相关系数对比法)
Apr 07 Python
python 如何调用远程接口
Sep 11 Python
一篇文章带你搞定Ubuntu中打开Pycharm总是卡顿崩溃
Nov 02 Python
使用pandas模块实现数据的标准化操作
May 14 Python
Python下opencv使用hough变换检测直线与圆
Jun 18 Python
在CentOS上配置Nginx+Gunicorn+Python+Flask环境的教程
Jun 07 #Python
Windows上使用virtualenv搭建Python+Flask开发环境
Jun 07 #Python
在Python的Flask中使用WTForms表单框架的基础教程
Jun 07 #Python
详解Python的Flask框架中生成SECRET_KEY密钥的方法
Jun 07 #Python
Python的Flask框架中配置多个子域名的方法讲解
Jun 07 #Python
python3批量删除豆瓣分组下的好友的实现代码
Jun 07 #Python
python实现多线程的方式及多条命令并发执行
Jun 07 #Python
You might like
让你的PHP同时支持GIF、png、JPEG
2006/10/09 PHP
PHP mail()函数使用及配置方法
2014/01/14 PHP
php中字符查找函数strpos、strrchr与strpbrk用法
2014/11/18 PHP
php文件上传简单实现方法
2015/01/24 PHP
PHP自带ZIP压缩、解压缩类ZipArchiv使用指南
2015/03/03 PHP
php实现基于PDO的预处理示例
2017/03/28 PHP
简单谈谈PHP面向对象之标识对象
2017/06/27 PHP
laravel 解决Validator使用中出现的问题
2019/10/25 PHP
JS中Iframe之间传值的方法
2013/03/11 Javascript
文本框水印提示效果的简单实现代码
2014/02/22 Javascript
jquery 隐藏与显示tr标签示例代码
2014/06/06 Javascript
jQuery焦点控制图层展示延迟隐藏的方法
2015/03/09 Javascript
JavaScript中的setMilliseconds()方法使用详解
2015/06/11 Javascript
jQuery学习笔记之Ajax用法实例详解
2015/12/01 Javascript
jQuery Easyui Tabs扩展根据自定义属性打开页签
2016/08/15 Javascript
详解Vue2.0组件的继承与扩展
2018/11/23 Javascript
JS实现移动端在线签协议功能
2019/08/22 Javascript
layui 数据表格 根据值(1=业务,2=机构)显示中文名称示例
2019/10/26 Javascript
JS实现公告上线滚动效果
2021/01/10 Javascript
python操作mysql中文显示乱码的解决方法
2014/10/11 Python
Python获取单个程序CPU使用情况趋势图
2015/03/10 Python
Python基于回溯法子集树模板解决0-1背包问题实例
2017/09/02 Python
Python3实现的判断回文链表算法示例
2019/03/08 Python
详解【python】str与json类型转换
2019/04/29 Python
django-filter和普通查询的例子
2019/08/12 Python
Selenium 配置启动项参数的方法
2020/12/04 Python
详解px单位html5响应式方案
2018/03/08 HTML / CSS
英国乡村时尚和宠物用品专家:Pet & Country
2018/07/02 全球购物
北美最大的手工艺品零售商之一:Michaels Stores
2019/02/27 全球购物
会计毕业生自荐信
2013/11/21 职场文书
个人作风纪律整顿整改措施
2014/10/25 职场文书
JavaScript 去重和重复次数统计
2021/03/31 Javascript
Mysql 用户权限管理实现
2021/05/25 MySQL
div与span之间的区别与使用介绍
2021/12/06 HTML / CSS
Python+Matplotlib+LaTeX玩转数学公式
2022/02/24 Python
TS 类型兼容教程示例详解
2022/09/23 Javascript