1.QQ第三方登录

QQ登录

QQ登录,亦即我们所说的第三方登录,是指用户可以不在本项目中输入密码,而直接通过第三方的验证,成功登录本项目。

若想实现QQ登录,需要成为QQ互联的开发者,审核通过才可实现。注册方法可参考链接http://wiki.connect.qq.com/%E6%88%90%E4%B8%BA%E5%BC%80%E5%8F%91%E8%80%85

成为QQ互联开发者后,还需创建应用,即获取本项目对应与QQ互联的应用ID,创建应用的方法参考链接http://wiki.connect.qq.com/__trashed-2

QQ登录开发文档连接http://wiki.connect.qq.com/%E5%87%86%E5%A4%87%E5%B7%A5%E4%BD%9C_oauth2-0

使用QQ登录的流程


QQ登录的大致流程为:

1.用户在浏览器点击QQ登录按钮,向后端发送请求,后端服务器根据用户传来的查询字符串中?next=xxxx(用于指定登录后跳转的页面,如果用户是通过点击个人中心来到登录页面,则登录成功后跳回用户中心),生成QQ登录页面的url并返回。

params = {
'response_type': 'code',
'client_id': self.client_id,
'client_secret': self.client_secret,
'redirect_uri': self.redirect_uri,
'state': self.state,
'scope': 'get_user_info',
}
url = 'https://graph.qq.com/oauth2.0/authorize?' + urlencode(params)
return url

2.前端得到qq登录页面的url,访问qq服务器,qq会将用户重定向到服务器的callback地址,并携带者code和state,state是第一步中的next,即登录后跳转的页面。

3.前端将向服务器发送请求,服务器获取code值后,向qq服务器发送请求,获取access_token,然后带者access_token再向qq服务器发送请求获取openid。得到openid后,在数据库中查询,是否已经绑定过帐号,如果有则签名并登录。如果没有,则返回加密后的openid到用户绑定页面。前端发送post请求将个人信息发送给服务器,服务器后端创建用户(如果已有则需要验证密码是否正确)并绑定qq。

附:

#QQ登录的参数
QQ_CLIENT_ID = 'xxxxxxx'
QQ_CLIENT_SECRET = 'xxxxx'
QQ_REDIRECT_URI = 'http://xxxxx:8080/oauth_callback.html'
QQ_STATE = '/'
获取code,access_token.opnid参见 QQ登录开发文档连接 http://wiki.connect.qq.com/%E5%87%86%E5%A4%87%E5%B7%A5%E4%BD%9C_oauth2-0

代码:

视图:

class QQAuthURLView(APIView):

def get(self,request):
"""
提供用于qq登录的url
"""
next = request.query_params.get( "next")
oauth = OAuthQQ(state = next)
login_url = oauth.get_qq_login_url()
return Response({ "login_url":login_url})
class QQAuthUserView(GenericAPIView):
"""
QQ登录的用户
"""
serializer_class = OAuthQQUserSerializer
def get(self,request):
"""
获取qq登录的用户数据
"""
code = request.query_params.get( 'code')
if not code:
return Response({ "message": "缺少code"},status =status. HTTP_400_BAD_REQUEST)
oauth = OAuthQQ()
#获取openid
try:
access_token = oauth.get_access_token(code)[ 0]
openid = oauth.get_openid(access_token)
except Exception:
return Response({ "message": "QQ服务器错误"})
#判断用户是否存在
try:
qq_user = OAuthQQUser.objects.get(openid =openid)
except OAuthQQUser.DoesNotExist:
#用户第一次登录
token = oauth.generate_sava_user_token(openid)
return Response({ "access_token":token})
else:
#用户不是第一次登录
user = qq_user.user
jwt_payload_handler = api_settings. JWT_PAYLOAD_HANDLER
jwt_encode_handler = api_settings. JWT_ENCODE_HANDLER
payload = jwt_payload_handler(user)
token = jwt_encode_handler(payload)
return Response({
"token":token,
"user_id":user.id,
"username":user.username
})
def post(self,request):
serializer = self.get_serializer(data =request.data)
serializer.is_valid(raise_exception = True)
user = serializer.save()
# 生成已登录的token
jwt_payload_handler = api_settings. JWT_PAYLOAD_HANDLER
jwt_encode_handler = api_settings. JWT_ENCODE_HANDLER
payload = jwt_payload_handler(user)
token = jwt_encode_handler(payload)
return Response({
'token':token,
'user_id':user.id,
'username':user.username
})

工具类:

class OAuthQQ( object):
"""
QQ认证工具类
"""
def __init__(self,client_id = None, client_secret = None,redirect_uri = None,state = None):
self.client_id = client_id or settings. QQ_CLIENT_ID
self.client_secret = client_secret or settings. QQ_CLIENT_SECRET
self.redirect_uri = redirect_uri or settings. QQ_REDIRECT_URI
self.state = state or settings. QQ_STATE #登录成功后跳转的页面
def get_qq_login_url(self):
"""
获取QQ登录的网址,构造参数返回前端
:return:
"""
params = {
'response_type': 'code',
'client_id': self.client_id,
'client_secret': self.client_secret,
'redirect_uri': self.redirect_uri,
'state': self.state,
'scope': 'get_user_info',
}
url = 'https://graph.qq.com/oauth2.0/authorize?' + urlencode(params)
return url
def get_access_token(self,code):
        #获取access_token
params = {
'grant_type': 'authorization_code',
'client_id': self.client_id,
'client_secret': self.client_secret,
'redirect_uri': self.redirect_uri,
'code':code
}
#生成请求access_token的url
url = 'https://graph.qq.com/oauth2.0/token?' +urlencode(params)
#发送请求
response = urlopen(url)
#返回来的值是二进制,要进行解码
response_data = response.read().decode()
#将查询字符串转为字典
data = parse_qs(response_data)
#获取access_token
access_token = data.get( 'access_token', None)
if access_token is None:
logger.error( "code= %s msg= %s " %(data.get( 'code'), data.get( 'msg')))
raise QQAPIError
return access_token
def get_openid(self,access_token):
"""
获取用户的openid
:param access_token: qq提供的access_token
:return: open_id
"""
url = 'https://graph.qq.com/oauth2.0/me?access_token=' +access_token
response = urlopen(url)
response_data = response.read().decode()
try:
# 返回的数据 callback( {"client_id":"YOUR_APPID","openid":"YOUR_OPENID"} )\n;
data = json.loads(response_data[ 10: - 4])
except Exception:
data = parse_qs(response_data)
logger.error( "code= %s ,msg= %s " %(data.get( "code"),data.get( 'msg')))
raise QQAPIError
openid = data.get( "openid")
return openid
@ staticmethod
def generate_sava_user_token(openid):
"""
生成保存用户数据的token,加密
:param openid: 用户的openid
:return: token
"""
serializer = Serializer(settings. SECRET_KEY, expires_in =constants. SAVE_QQ_USER_TOKEN_EXPIRES)
data = {
"openid":openid
}
token = serializer.dumps(data)
return token.decode()
@ staticmethod
def check_save_user_token(token):
"""
检验保存用户数据的token
:param token: token
:return: openid or None
"""
serializer = Serializer(settings. SECRET_KEY, expires_in =constants. SAVE_QQ_USER_TOKEN_EXPIRES)
try:
data = serializer.loads(token)
except BadData:
return None
else:
return data.get( "openid")

猜你喜欢

转载自blog.csdn.net/wang785994599/article/details/80834350
今日推荐