三方登录(微博为例)
三方登录介绍
- 三方登录流程(以微博为例)
1)前端获取认证code
1. 在Vue页面加载时动态发送请求获取微博授权url
2. django收到请求的url后,通过微博应用ID(client_id)和回调地址(redirect_uri)动态生成授权url返回给Vue
3. 当用户点击上面的url进行扫码,授权成功会跳转我们的回调界面并附加code参数
4. Vue获取到微博返回的code后,会将code发送给django后端(上面的redirect_uri)
2)获取微博access_token
后端获取code后,结合client_id、client_secret、redirect_uri参数进行传递
获取微博access_token
3)获取微博用户基本信息并保存到数据库
使用获得的access_token调用获取用户基本信息的接口,获取用户第三方平台的基本信息
用户基本信息保存到数据库,然后关联本地用户,然后将用户信息返回给前端
4)生成token给Vue
django后端借助微博认证成功后,可以使用JWT生成token,返回给Vue
Vue将token存储到localStorage中,以便用户访问其他页面进行身份验证
oauth认证原理
- OAuth是一个开放标准,允许用户让第三方应用访问该用户在某一网站上存储的私密的资源,而无需将用户名和密码提供给第三方应用
- OAuth允许用户提供一个令牌,而不是用户名和密码来访问他们存放在特定服务提供者的数据
- 这个code如果能出三方换取到数据就证明这个用户是三方真实的用户
为什么使用三方登录
- 服务方希望用户注册, 而用户懒得填注册时的各种信息(主要是为了保证用户的唯一性,各种用户名已占用,密码格式限制)
- 而像微信, QQ, 微博等几乎每个人都会安装的应用中用户肯定会在其中某一个应用中已经注册过,证明该用户在已经注册的应用中的唯一性
- 第三方登录的实质就是在授权时获得第三方应用提供的代表了用户在第三方应用中的唯一性的openid.并将openid储存在第三方服务控制的本地储存
第三方登录与本地登录的关联(三种情况)
1)情况1: 本地未登录,第一次登录第三方
此时相当于注册,直接把第三方信息拉取来并注册成本地用户就可以了,并建立本地用户与第三方用户(openid)的绑定关系
2)情况2:本地未登录,再次登录第三方
此时用户已注册,获取到openid后直接找出对应的本地用户即可
3)情况3:本地登录,并绑定第三方
这个只要将获取到的openid绑定到本地用户就可以了
微博申请应用
微博申请应用参考:https://cloud.tencent.com/developer/article/1441425
官方微博接入文档:https://open.weibo.com/wiki/Connect/login
- 前端Vue
vue init webpack webssh
npm install --save axios
src\router\index.js 添加路由
import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'
import Login from '@/components/Login'
import WeiboCallback from '@/components/WeiboCallback'
import UserBind from '@/components/UserBind'Vue.use(Router)export default new Router({mode: 'history',routes: [{ path: '/', name: 'HelloWorld', component: HelloWorld },{ path: '/login', name: 'Login', component: Login }, // 登录页面{ path: '/weibo_callback', name: 'WeiboCallback', component: WeiboCallback }, // 通过空页面发送code给后端{ path: '/userbind', name: 'UserBind', component: UserBind }, // 将本地用户与第三方用户绑定]
})
src\components\Login.vue 登录页面
<template><div><a :href="weibo_url" class="weibo_login">微博</a></div>
</template><style></style><script>import axios from "axios";export default {data: function(){return {weibo_url: '' // 动态从后端获取的微博扫码URL}},mounted(){this.get_weibo_url()},methods: {get_weibo_url: function(){// http://127.0.0.1:8000/api/weibo_url/axios({url: 'http://127.0.0.1:8000/api/weibo_url/',method: 'get'}).then(res=>{this.weibo_url = res.data.weibo_url})}}};
</script>
src\components\WeiboCallback.vue 通过空页面发送code给后端
<template><p>跳转中....</p>
</template><script>
import axios from 'axios'
export default {mounted(){this.get_code()},methods: {get_code: function(){let code = this.$route.query.code // 获取微博的验证codeconsole.log(code)axios({url:'http://127.0.0.1:8000/api/weibo_back/?code=' + code,method: 'get'}).then(res=>{console.log(res)if (res.data.code == 200) {console.log('成功')localStorage.username = res.data.usernamelocalStorage.user_id = res.data.user_idlocalStorage.token = res.data.tokenwindow.location.href = '/'}if (res.data.code == 201) {console.log('失败') // 如果用户未绑定,跳转到绑定页面localStorage.access_token = res.data.responsewindow.location.href = '/userbind'}})}}
}
</script>
src\components\UserBind.vue 将本地用户与第三方用户绑定
<template><div><form @submit.prevent="send_bind_info"><p><label>输入账号:</label><input type="account" name="account" id="account" v-model="account"></p><p><label>输入密码:</label><input type="password" name="pwd" id="pwd" v-model="password"></p><p><input type="submit" value="注 册" name></p></form></div></div>
</template><style></style><script>
document.title = "绑定页面";
import axios from "axios";
export default {// axios-> access_tokendata: function() {return {password: "",account: "",};},methods: {send_bind_info: function() {let post_data = new FormData();let access_token = localStorage.access_token;post_data.append("password", this.password);post_data.append("account", this.account);post_data.append("access_token", access_token);axios({url: "http://127.0.0.1:8000/api/bind_user/",method: "post",data: post_data}).then(res => {});}}
};
</script>
- django后端
# requirements.txt
Django==2.0.4
djangorestframework==3.9.2
djangorestframework-jwt==1.11.0
django-cors-headers==3.0.2
settings.py 配置使用JWT、corsheaders、rest_framework
INSTALLED_APPS = ['rest_framework.authtoken','rest_framework', 'users','corsheaders',
]MIDDLEWARE = ['corsheaders.middleware.CorsMiddleware',# 'django.middleware.common.CommonMiddleware',
]''' 配置jwt验证 '''
REST_FRAMEWORK = {# 身份认证'DEFAULT_AUTHENTICATION_CLASSES': ('rest_framework_jwt.authentication.JSONWebTokenAuthentication','rest_framework.authentication.SessionAuthentication','rest_framework.authentication.BasicAuthentication',),
}
import datetime
JWT_AUTH = {'JWT_AUTH_HEADER_PREFIX': 'JWT','JWT_EXPIRATION_DELTA': datetime.timedelta(days=1),'JWT_RESPONSE_PAYLOAD_HANDLER':'users.views.jwt_response_payload_handler', # 重新login登录返回函数
}
AUTH_USER_MODEL='users.User' # 指定使用users APP中的 model User进行验证'''配置cors'''
CORS_ALLOW_CREDENTIALS = True
CORS_ORIGIN_ALLOW_ALL = True'''微博相关配置信息'''
WEIBO_APP_KEY = '3516473472'
WEIBO_APP_SECRET = '7862ee35a0dc6f0345d0464dc34f14fc'
WEIBO_FUNC_BACK = 'http://127.0.0.1:8080/weibo_callback' # VUE的回调
urls.py 总路由
from django.contrib import admin
from django.urls import path,includeurlpatterns = [path('admin/', admin.site.urls),path('api/', include('users.urls')),
]
users/urls.py
#! /usr/bin/env python
# -*- coding: utf-8 -*-
from django.urls import path,re_path
from . import views
urlpatterns = [re_path(r'register/',views.RegisterView.as_view(),name='register'),re_path(r'weibo_url/', views.WeiboUrl.as_view(), name='weibo_url'),re_path(r'weibo_back/',views.WeiboBack.as_view(),name='weibo_back'),re_path(r'bind_user/',views.BindUser.as_view(),name='bind_user'),
]
users/models.py
from django.db import models
from django.contrib.auth.models import AbstractUserclass User(AbstractUser):username = models.CharField(max_length=64, unique=True)password = models.CharField(max_length=255)phone = models.CharField(max_length=64,blank=True,null=True)class SocialUser(models.Model):user = models.ForeignKey(User,on_delete=models.CASCADE,verbose_name='用户')platfrom_type_choices = ((1,'web'),(2,'移动'),)platfrom_ID = models.IntegerField(choices=platfrom_type_choices,verbose_name='平台类型')platfrom_choices = ((1,'QQ'),(2,'微博'),(3,'微信'),)platfrom_type = models.IntegerField(choices=platfrom_choices,verbose_name='社交平台')uid = models.CharField(max_length=100,verbose_name='用户ID')def __str__(self):return self.user.username
users/serializers.py
#! /usr/bin/env python
# -*- coding: utf-8 -*-
from rest_framework_jwt.settings import api_settings
from rest_framework import serializers
from users.models import User
from users.models import SocialUserclass UserSerializer(serializers.Serializer):username = serializers.CharField()password = serializers.CharField()phone = serializers.CharField(required=False,allow_blank=True)token = serializers.CharField(read_only=True)def create(self, data):user = User.objects.create(**data)user.set_password(data.get('password'))user.save()# 补充生成记录登录状态的tokenjwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLERjwt_encode_handler = api_settings.JWT_ENCODE_HANDLERpayload = jwt_payload_handler(user) # 创建载荷token = jwt_encode_handler(payload) # 创建tokenuser.token = tokenreturn userclass SocialUserSerializer(serializers.Serializer):user_id = serializers.IntegerField()platfrom_ID = serializers.IntegerField() # 平台类型(web/移动)platfrom_type = serializers.IntegerField() # 社交平台(微博/微信/QQ)uid = serializers.IntegerField() # 社交平台唯一IDdef create(self, validated_data):social_user = SocialUser.objects.create(**validated_data)return social_user
users/views.py
from django.shortcuts import render
import json
from rest_framework.views import APIView
from rest_framework.views import Response
from rest_framework.permissions import IsAuthenticated
from rest_framework_jwt.authentication import JSONWebTokenAuthentication
from urllib.parse import urlencode
import requests
from rest_framework_jwt.settings import api_settings
from django.db import transaction
from rest_framework import serializers
from django.core.exceptions import ValidationErrorfrom weiboLogin import settings
from users import models
from users.serializers import UserSerializer
from users.serializers import SocialUserSerializer# 用户注册
class RegisterView(APIView):def post(self, request, *args, **kwargs):serializer = UserSerializer(data=request.data)if serializer.is_valid():serializer.save()return Response(serializer.data, status=201)return Response(serializer.errors, status=400)# 重写用户登录返回函数
def jwt_response_payload_handler(token, user=None, request=None):''':param token: jwt生成的token值:param user: User对象:param request: 请求'''return {'test':'aaaa','token': token,'user': user.username,'userid': user.id}# 生成前端跳转到微博扫码页面的url
class WeiboUrl(APIView):'''生成微博的登陆页面路由地址https://api.weibo.com/oauth2/authorize? # 微博oauth认证地址client_id=4152203033& # 注册开发者idresponse_type=code&redirect_uri=http://127.0.0.1:8080/weibo_callback/ # 获取code后将code回调给后端地址'''def get(self, request):url = 'https://api.weibo.com/oauth2/authorize?'data = {'client_id': settings.WEIBO_APP_KEY,'response_type': 'code','redirect_uri': settings.WEIBO_FUNC_BACK,}weibo_url = url + urlencode(data)# https://api.weibo.com/oauth2/authorize?client_id=4152203033&response_type=code&redirect_uri=http://127.0.0.1:8000/api/weibo_back/return Response({'weibo_url': weibo_url})# 微博扫码成功后携带code调用此接口,认证成功返回jwt token
class WeiboBack(APIView):'''通过回调连接,获取access_tokenhttps://api.weibo.com/oauth2/access_token?client_id=YOUR_CLIENT_IDclient_secret=YOUR_CLIENT_SECRET&grant_type=authorization_code&code=CODEredirect_uri=YOUR_REGISTERED_REDIRECT_URI'''def get(self, request):code = request.query_params.get('code') # code为微博微博认证的codedata = {'client_id': settings.WEIBO_APP_KEY,'client_secret': settings.WEIBO_APP_SECRET,'grant_type': 'authorization_code','code': code,'redirect_uri': settings.WEIBO_FUNC_BACK,}url = 'https://api.weibo.com/oauth2/access_token'response = requests.post(url=url, data=data).json() # 拿取请求的返回结果# {'access_token': '2.00jqYNTGfgNAXEbd85e6c672uTGF8E',# 'remind_in': '157679999', 'expires_in': 157679999,# 'uid': '5928542965', 'isRealName': 'true'}print(response)uid = response.get('uid') # uid是微博三方的唯一idif not uid: # 获取不到则为微博code错误return Response({'code': 201, 'error': '三方授权失败'})try:# 判断当前UID是否存在与数据库中,如果存在,代表用户可以登陆的user = models.SocialUser.objects.get(uid=uid)except:# 如果不存在,代表这个用户不能登陆,先得跳转到绑定页面,将本地用户与微博用户进行绑定return Response({'code': 201,'response': json.dumps(response)})else: # 如果获取到uid,就生成token返回给vuejwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLERjwt_encode_handler = api_settings.JWT_ENCODE_HANDLERpayload = jwt_payload_handler(user.user) # 创建载荷token = jwt_encode_handler(payload) # 创建tokenreturn Response({'code': 200,'token': token,'username': user.user.username,'user_id': user.user.id,})# 将微博用户绑定到本地用户
class BindUser(APIView):def post(self, request):account = request.data.get('account') # 绑定的账号password = request.data.get('password') # 绑定的密码user_url = "https://api.weibo.com/2/users/show.json?access_token=%s&uid=%s"access_token = json.loads(request.data.get('access_token'))get_url = user_url % (access_token['access_token'], access_token['uid'])# {'access_token': '2.00jqYNTGfgNAXEbd85e6c672uTGF8E','uid': '5928542965', 'isRealName': 'true'}data = requests.get(url=get_url).json() # 通过token获取微博详细信息if data.get('error'):return Response({'code': 201,'token': access_token,})else:try:serializer = UserSerializer(data={'username':account,'password':password})if serializer.is_valid():# 创建本地用户与微博用户关联with transaction.atomic():save_id = transaction.savepoint() # 创建一个保存点try:user = serializer.save()socialuser = SocialUserSerializer(data={"user_id": user.id,"platfrom_ID" : 1,"platfrom_type": 2,"uid" : data['id']})if socialuser.is_valid():socialuser.save()return Response({'code': 200,'token': user.token,'username': user.username,'user_id': user.id,})else:transaction.savepoint_rollback(save_id) # 出现异常退回到保存点except ValidationError:raiseexcept Exception as e:transaction.savepoint_rollback(save_id)finally:# 提交事务transaction.savepoint_commit(save_id)except Exception as e:print(e)return Response(status=400)
详情链接参考
三方登录(微博为例)相关推荐
- pc端和移动端集成第三方快捷登录 --- 微博为例
通过新浪微博的开放平台去注册一个应用. 之后你会得到一个App Key和一个App Secret.拥有它们,你才可以申请权限. 2.在高级信息中编辑授权回调页,这里与后面代码里的回调地址要一致 3. ...
- php 微信第三方登录demo,第三方登录 - 快速接入微信、QQ、微博等第三方登录方式 – 基于ThinkPHP和Bootstrap的极速后台开发框架...
此插件基于FastAdmin和Thinkphp5开发的第三方登录插件,可用于对接微.微博.QQ等第三方登录,目前CMS中的小程序账号登录绑定就是基于此插件开发,在使用CMS中的小程序登录功能之前请务必 ...
- 以微博为例进行Oauth2进行第三方授权登录
OAuth2.0:对于用户相关的 OpenAPI(例如获取用户信息,动态同步,照片,日志,分享等),为了保护用户数据的安全和隐私,第三方网站访问用户数据前都需要显式的向用户征求授权. 流程: (A)用 ...
- 安卓三方登录趟坑,QQ,微信,微博,Twitter,Facebook,Instagram
前言 最近给app加入三方登录,由于比较多,所以就用的友盟统一登录,会比一个一个配置方便点 正文 先说QQ,微信,微博: 国内QQ,微信,微博三方登录其实还行,并没有太多坑,文档也挺完善的. 但是需要 ...
- 微博三方登录原理讲解
微博三方登录流程 1.1 前端获取认证code 1.在Vue页面加载时 动态发送请求获取微博授权url 2.django收到请求的url后,通过微博 应用ID(client_id)和回调地址(redi ...
- A072_前台登录_三方登录
目录 内容介绍 1. 前台登录-账号登录 1.1.前台登录 1.2.axios携带token-common.js 1.3.axios后置处理后台拦截错误-common.js 1.4.前台登录拦截-co ...
- 兄弟们,就是干 微信三方登录绝对干货
微信第三方登录绝对干货 课程介绍 1. 用户登录-账号登录;(掌握) 2. 三方登录概述;(理解) 3. 三方登录协议-Oauth2.0;(了解) 4. 三方登录选择-微信三方登录;(掌握) ...
- Android 集成ShareSDK实现三方登录
** 前言 ** 三方登录在如今差不多已经成为每一款App必备的功能了.每次集成都会遇到各种各样的问题,今天总结一下三方登录的流程,以免忘记.现在好像还没有专门的三方登录SDK,ShareSDK和友盟 ...
- [OAuth2.0三方登录系列文章-1]OAuth2.0与三方登录的端到端方案
系列文章 [OAuth2.0三方登录系列文章-1]OAuth2.0与三方登录的端到端方案 [OAuth2.0三方登录系列文章-2]如何设计基于OAuth2.0的授权登录SDK以及竞品分析 [OAuth ...
最新文章
- 事件委托技术原理和使用(js,jquery)
- SQL Server2005完全卸载
- 【并查集】并查集的基本操作总结
- SpringMVC的数据响应方式-页面跳转
- clientdataset 遍历字段_Delphi TClientDataSet[五]: 读取数据
- mongodb安装、远程访问设置、管理命令、增删改查操作以及GUI
- TabControl 切换 内嵌web页面直接响应滚动事件
- qq群机器人宠物系统java_QQ群机器人——宠物游戏
- sox 转换pcm格式采样率
- 3GPP TS 24.301 Release 8 中文版
- 回首2021,展望2022 | 观成科技步履不停,刻画安全图腾
- Related Problems
- Android如何自定义服务器DynamicMockServer的使用
- 闲聊----Simulation,MSaaS到SaaS
- 【NLP】keras Transformer 唐诗生成器
- Swing学习----------QQ登录界面制作(一)
- 【转】经典论文翻译导读之《A Bloat-Aware Design for Big Data Applications》
- python数据分析-互联网业务数据分析流程及指标体系的搭建
- 金融外包测试项目经验分享
- OSCP证书考试总结与终身学习 - 带你走上 OSCE3
热门文章
- 爆料!亦庄地区数据中心将面临史上最长群体”限电“
- 成功解决ModuleNotFoundError: No module named ‘torch._C‘
- ML之XGBoost:XGBoost参数调优的优秀外文翻译—《XGBoost中的参数调优完整指南(带python中的代码)》(二)
- 成功解决TypeError: a bytes-like object is required, not 'str'
- DL之DNN之BP:神经网络算法简介之BP算法/GD算法之不需要额外任何文字,只需要八张图讲清楚BP类神经网络的工作原理
- Python之tkinter:动态演示调用python库的tkinter带你进入GUI世界(text.insert/link各种事件)
- 5.2 TensorFlow:模型的加载,存储,实例
- Linux 静态库 动态库
- PHPsession工作机制以及销毁session
- jmeter脚本结合ant执行测试用例并生成测试报告