一、判断openid是否绑定过⽤户
使⽤openid查询该QQ⽤户是否在芒果头条中绑定过⽤户。
openid已绑定⽤户的处理:
如果openid已绑定芒果头条⽤户,直接⽣成状态保持信息,登录成功,并重定向到⾸⻚。
openid未绑定⽤户的处理:
为了能够在后续的绑定⽤户操作中前端可以使⽤openid,在这⾥将openid签名后响应给前端。
openid属于⽤户的隐私信息,所以需要将openid签名处理,避免暴露。
openid未绑定用户时,进入这个页面
二、itsdangerous的使⽤
安装:
pip install itsdangerous
定义utils.py文件
定义方法:实现对openid进行加密和对openid进行解密
from django.conf import settings
from itsdangerous import TimedJSONWebSignatureSerializer as Serializer, BadData
def generate_secret_openid(openid):
"""
签名openid
:param openid: 用户的openid
:return: access_token
"""
# 创建序列化器对象给数据加密
serializer = Serializer(settings.SECRET_KEY,expires_in=600)
data = {'openid': openid}
token = serializer.dumps(data)
return token.decode()
def check_secret_openid(sec_openid):
"""
反解、反序列化access_token_openid
:param access_token_openid: openid密文
:return: openid明文
"""
# 创建序列化器对象:序列化和反序列化的对象的参数必须是一模一样的
s = Serializer(settings.SECRET_KEY, expires_in=600)
# 反序列化openid密文
try:
data = s.loads(sec_openid)
except BadData: # openid密文过期
return None
else:
# 返回openid明文
return data.get('openid')
三、QQ用户绑定项目用户功能实现
类似于⽤户注册的业务逻辑
当⽤户输⼊的⼿机号对应的⽤户已存在
直接将该已存在⽤户跟openid绑定。
当⽤户输⼊的⼿机号对应的⽤户不存在
新建⼀个⽤户,并跟openid绑定。
# Create your views here.
import re
import django_redis
from django.contrib.auth import login
from django.http import JsonResponse, HttpResponse
from django.shortcuts import render, redirect,reverse
from AgentLogin import AgentLogin
from django.views.generic.base import View
from django.conf import settings
from django import http
from .models import QQAuthUser
from mgproject.apps.oauth.utils import generate_secret_openid
from .utils import check_secret_openid
from userapp.models import Users
class QQLoginURLView(View):
def get(self,request):
'''
获取qq扫码登陆连接地址
:param request:
:return:
'''
qq_url=AgentLogin.qq_url(client_id=settings.QQ_CLIENT_ID,redirect_url=settings.QQ_REDIRECT_URI)
return JsonResponse({'code':200,'errormsg':'ok','login_url':qq_url})
class QQAuthUserView(View):
def get(self,request):
'''
获取openis
:param request:
:return:
'''
#获取code参数
code=request.GET.get('code','')
#校验参数
if not code:
return http.HttpResponseForbidden('缺少code参数')
#调用接口方法获取openid
nickname,openid=AgentLogin.qq(client_id=settings.QQ_CLIENT_ID,
client_secret=settings.QQ_APP_KEY,
url=settings.QQ_REDIRECT_URI,
code=code)
#通过openid判断qq用户是否绑定项目用户
try:
qq_user=QQAuthUser.objects.get(openid=openid)
except QQAuthUser.DoesNotExist:
#qq用户没有绑定项目用户
#加密openid数据
sec_openid=generate_secret_openid(openid)
#传递加密数据给用户绑定页面
return render(request,'oauth/oauth_user.html',{'sec_openid':sec_openid})
else:
#qq用户绑定了项目用户
#获取关联的项目用户对象
user=qq_user.user
#状态保持
login(request,user)
#响应结果
return redirect(reverse('newsapp:index'))
def post(self,request):
'''
将当前访问QQ用户绑定项目用户
:param request:
:return:
'''
#1、接收参数
sec_openid=request.POST.get('sec_openid','')
phone=request.POST.get('phone','')
sms_code_client=request.POST.get('msgcode','')
pwd=request.POST.get('password','')
#2、校验参数
#非空校验
if not all([sec_openid,phone,sms_code_client,pwd]):
return http.HttpResponseForbidden('缺少必传参数')
#判断手机号是否合法
if not re.match(r'^1[35789]\d{9}$', phone):
return http.HttpResponseForbidden('请输⼊正确的⼿机号码')
#判断密码是否合法
if not re.match(r'^[0-9A-Za-z]{3,8}$', pwd):
return http.HttpResponseForbidden('请输⼊3,8位的密码')
#判断短信验证码是否一致
redis_conn=django_redis.get_redis_connection('verify_code')
sms_code_server=redis_conn.get('sms_%s'%phone)
if sms_code_server is None:
return render(request,'oauth/oauth_user.html',{'sms_code_errmg':'无效的短信验证码'})
if sms_code_server.decode()!=sms_code_client:
return render(request,'oauth/oauth_user.html',{'sms_code_error':'输入的短信验证码错误'})
#3、绑定用户
#判断当前qq用户是否合法(解密openid数据)
openid=check_secret_openid(sec_openid)
if not openid:
return render(request, 'oauth/oauth_user.html', {'openid_errmg': 'openid已经实效'})
#获取项目用户
try:
user=Users.objects.get(phone=phone)
except Users.DoesNotExist:
#创建项目新用户
user=Users.objects.create_user(username=phone,password=pwd,phone=phone)
else:
#判断项目用户密码是否正确
if not user.check_password(pwd):
return render(request,'oauth/oauth_user.html',{'qq_login_errmsg':'用户名或者密码错误'})
#绑定用户
QQAuthUser.objects.create(user=user,openid=openid)
#状态保持
login(request,user)
#4、返回结果
return redirect(reverse('newsapp:index'))