QQ登录
我们所说的第三方登录,是指用户可以不在本项目中输入密码,而直接通过第三方的验证,成功登录荏苒网。
要开发第三方登录功能,必须要成为QQ互联开发者后,创建应用,即获取当前项目与QQ互联的应用ID,创建应用的方法参考链接http://wiki.connect.qq.com/__trashed-2
申请创建开发应用以后, 需要经过人工审核,这个时间一般是一个工作日或者半个工作日.
审核的状态会影响我们开发者开发第三方登录,状态有三种:
1. 不通过和未审核的应用,是无法开发QQ第三方登录功能的.
2. 只有已通过的应用才可以开发
点击刚才申请的引用,进入到项目里面获取APPID和APP KEY.
QQ登录开发文档连接http://wiki.connect.qq.com/%E5%87%86%E5%A4%87%E5%B7%A5%E4%BD%9C_oauth2-0
QQ第三方登录的实现流程
创建模型类
创建一个新的应用oauth,用来实现QQ第三方认证登录。
cd renranapi/apps
python ../../manage.py startapp oauth
注册子应用 settings/dev.py,代码:
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'corsheaders',
'xadmin',
'crispy_forms',
'reversion',
'rest_framework',
'users',
'oauth',
]
在models.py中定义QQ身份(openid)与用户模型类User的关联关系
from django.db import models
# Create your models here.
from django.db import models
from renranapi.utils.models import BaseModel
from users.models import User
class OAuthUser(BaseModel):
"""
登录用户数据
"""
user = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name='用户')
openid = models.CharField(max_length=64, verbose_name='openid', db_index=True)
access_token = models.CharField(max_length=500,verbose_name="临时访问票据", help_text="有效期:3个月")
refresh_token = models.CharField(max_length=500,verbose_name="刷新访问票据的token", help_text="当access_token以后,可以使用refresh_token来重新获取新的access_token")
class Meta:
db_table = 'rr_oauth_qq'
verbose_name = 'QQ登录用户数据'
verbose_name_plural = verbose_name
在utils/models.py,创建项目的公共模型
from django.db import models
class BaseModel(models.Model):
"""基本公共模型"""
orders = models.IntegerField(default=0, null=True, blank=True, verbose_name="排序")
is_show = models.BooleanField(default=True, verbose_name="是否展示")
is_deleted = models.BooleanField(default=False, verbose_name="是否删除")
created_time = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
updated_time = models.DateTimeField(auto_now=True, verbose_name="更新时间")
class Meta:
abstract = True
进行数据库迁移
python manage.py makemigrations
python manage.py migrate
urllib使用说明
在后端接口中,我们需要向QQ服务器发送请求,查询用户的QQ信息,Python提供了标准模块urllib可以帮助我们发送http请求。
-
urllib.parse.urlencode(query)
将query字典转换为url路径中的查询字符串
-
urllib.parse.parse_qs(qs)
将qs查询字符串格式数据转换为python的字典
-
urllib.request.urlopen(url, data=None)
发送http请求,如果data为None,发送GET请求,如果data不为None,发送POST请求
返回response响应对象,可以通过read()读取响应体数据,需要注意读取出的响应体数据为bytes类型
代码实现
-
在settings/dev.py中增加QQ登录相关配置
# QQ登录参数
QQ_APP_ID = '101403367'
QQ_APP_KEY = '93112df14c10d6fde74baa62f5de95ab'
QQ_REDIRECT_URL = 'http://www.moluo.net:8080/oauth_callback.html'
QQ_STATE = "/" # 用于保存登录成功后的跳转页面路径
-
在oauth子应用下,创建utils.py文件,编写QQ登录的辅助类
from urllib.parse import urlencode, parse_qs
from urllib.request import urlopen
from django.conf import settings
import logging
logger = logging.getLogger('django')
class OAuthQQ(object):
"""
QQ认证辅助工具类
"""
def __init__(self, app_id=None, app_key=None, redirect_uri=None, state=None):
self.app_id = app_id or settings.QQ_APP_ID
self.app_key = app_key or settings.QQ_APP_KEY
self.redirect_url = redirect_uri or settings.QQ_REDIRECT_URL
self.state = state or settings.QQ_STATE # 用于保存登录成功后的跳转页面路径
def get_auth_url(self):
"""
获取qq登录的网址
:return: url网址
"""
params = {
'response_type': 'code',
'client_id': self.app_id,
'redirect_uri': self.redirect_url,
'state': self.state,
'scope': 'get_user_info',
}
url = 'https://graph.qq.com/oauth2.0/authorize?' + urlencode(params)
return url
视图代码:
from rest_framework.views import APIView
from .utils import OAuthQQ
from rest_framework.response import Response
class OAuthQQAPIView(APIView):
def get(self, request):
"""生成QQ登录的地址"""
state = request.query_params.get('state') # 客户端指定的状态
oauth = OAuthQQ(state=state)
url = oauth.get_auth_url()
print(url)
return Response(url)
路由,代码:
# 子应用代码:
from django.urls import path
from . import views
urlpatterns = [
path("qq/url/", views.OAuthQQAPIView.as_view() ),
]
# 总路由:
path('oauth/', include("oauth.urls")),
客户端请求获取QQ第三方登录地址
修改Login.vue,,在methods中增加qq_login方法
<template>
<div class="sign">
<div class="logo"><router-link to="/"><img src="/static/image/nav-logo.png" alt="Logo"></router-link></div>
<div class="main">
<h4 class="title">
<div class="normal-title">
<router-link class="active" to="/user/login">登录</router-link>
<b>·</b>
<router-link id="js-sign-up-btn" class="" to="/user/register">注册</router-link>
</div>
</h4>
<div class="js-sign-in-container">
<form id="new_session" action="" method="post">
<div class="input-prepend restyle js-normal">
<input placeholder="手机号或邮箱" type="text" v-model="username" id="session_email_or_mobile_number">
<i class="iconfont ic-user"></i>
</div>
<!-- 海外登录登录名输入框 -->
<div class="input-prepend">
<input placeholder="密码" type="password" v-model="password" id="session_password">
<i class="iconfont ic-password"></i>
</div>
<div class="remember-btn">
<input type="checkbox" value="true" checked="checked" v-model="remember_me" id="session_remember_me"><span>记住我</span>
</div>
<div class="forget-btn">
<a class="" data-toggle="dropdown" href="">登录遇到问题?</a>
</div>
<button class="sign-in-button" id="sign-in-form-submit-btn" type="button" @click="show_captcha">
<span id="sign-in-loading"></span>
登录
</button>