django实现,微博第三方登录超详细
前言:Vue Django 的跨域已经解决,Vue 是一个已经存在的项目 美化后的页面都是已经存在的,数据库的表格都已存在。核心思想:在微博开放平台 创建网页应用通过微博规定的 规格参数换取审核全部通过 登录信息入库判断登录的 新老用户 是否绑定邮箱登录微博开放平台,如果是新用户会审核一些东西,可以略过那些,选择性填写。。注册好应用后我们不需要 填写那些 信息,我们主要用到...
登录流程
- 前端获取认证code
- 在Vue页面加载时动态发送请求获取微博授权url
- django收到请求的url后,通过微博应用ID(client_id)和回调地址(redirect_uri)动态生成授权url返回给Vue
- 当用户点击上面的url进行扫码,授权成功会跳转我们的回调界面并附加code参数
- Vue获取到微博返回的code后,会将code发送给django后端(上面的redirect_uri)
-
获取微博access_token
后端获取code后,结合client_id、client_secret、redirect_uri参数进行传递,获取微博access_token -
获取微博用户基本信息并保存到数据库
使用获得的access_token调用获取用户基本信息的接口,获取用户第三方平台的基本信息
用户基本信息保存到数据库,然后关联本地用户,然后将用户信息返回给前端 -
生成token给Vue
django后端借助微博认证成功后,可以使用JWT生成token,返回给Vue
Vue将token存储到localStorage中,以便用户访问其他页面进行身份验证
前言:Vue Django 的跨域已经解决,Vue 是一个已经存在的项目 美化后的页面都是已经存在的,数据库的表格都已存在。
核心思想:
- 在微博开放平台 创建网页应用
- 通过微博规定的 规格参数换取
- 审核全部通过 登录信息入库
- 判断登录的 新老用户 是否绑定邮箱
登录微博开放平台,如果是新用户会审核一些东西,可以略过那些,选择性填写。。
注册好应用后我们不需要 填写那些 信息,我们主要用到的是这两个参数,是会用它去调取微博的各项参数最后换取 登录权
设置回调页,就是说登陆之后的跳转页面
查看获取第三方登录权限的文档
(这里很重要)
我们只会用到这三个授权,看一下里面的文档。(将三个文档全部观看)
这些文档中的返回值字段,只要是 True 形式的就必须填写,执行流程就是 这三个图片中的字段,在接口中对应的去请求。
比如第一张图片所需的参数,去请求给定的 url,就会获取到 对应的参数 然后在去请求下一个url。第三方登录就完成了。
首先 已知的条件
App Key:2851645393
App Secret:e646691419daa4bcb80c1bd95164b583
Url:https://api.weibo.com/oauth2/authorize (第一个文档中 给定好的)
CallBack: http://127.0.0.1:8080/course_index
由文档可知(文档在上面的截图) :
1. client_id true string 申请应用时分配的AppKey。
2. redirect_uri true string 授权回调地址,站外应用需与设置的回调地址一致,站内应用需填写canvas page的地址。
注:文档中的参数 字段 必须要遵守,字段名也要一致
我们预热一下,点击查看我拼接查看好的地址 https://api.weibo.com/oauth2/authorize?client_id=2851645393&redirect_uri=http://127.0.0.1:8080/course_index。
可以点击扫描二维码,毕竟登陆快、哈哈
如果:
再多次尝试登陆之后会出现这样的页面代表着,浏览器已经存储了登录的Cookie Token 清楚浏览器数据缓存就 OK。像下面这样
当然你也可以直接授权,但是 后期的 保存登录状态就 不好设置了 会重叠 不利于 浏览。
好了现在写后台接口请求对应的 url
写 接口之前 先把前台的 扫码前地址和扫码后的地址 写好。这里我用的是 Vue.js 前端框架。
//这是项目首页的 a 标签
<a href="https://api.weibo.com/oauth2/authorize?client_id=598520287&redirect_uri=http://127.0.0.1:8080/weibo_callback
"><i class="fa fa-weibo"></i></a>
看一下 效果
我们点击扫码登陆后 (没写跳转后的页面肯定有报错)发现 url 收到了 code 参数
写一个 Vue 页面接收这个 code 然后发送给后台 Django。
<template>
<div id="weibo_callback">
<h3>{{message}}</h3>
</div>
</template>
<script>
import axios from 'axios'
export default {
name: "weibo_callback",
data() {
return{
message:''
}
},
mounted() {
var code = this.$route.query.code;
var form_data = new FormData();
form_data.append('code', code);
console.log(code);
axios({
'url': 'api/user/get_weibo_code/',
'method': 'post',
'data': form_data
})
我们通过 Vue 的 this.$route.query 获取到 code 值,然后存放到 FormData 发送到后台。
到这里我 有一个 思想,定义一个 类 然后 去换取参数的用另外定义的方法–(此时用到的函数试图是不配置路由的,他们只是换取所需值的方法,最终都是类试图进行调取)
用类试图接收 code 值,再用函数方法去请求 weibo api接口
# 接收 微博回调页面 发送的 code
class Get_WeiBo_Code(APIView):
def post(self, request):
code = request.data['code']
# views.py
# Vue 发送的 不是这个接口 在下面 那个类试图
# 通过 授权过的 token 获取 Access_token
def get_weibo_accesstoken(code):
# 获取 access_token 的必要参数 ↓
url = 'https://api.weibo.com/oauth2/access_token'
data = {
'client_id': '2851645393', # 创建应用的 App Key
'client_secret': '646691419daa4bcb80c1bd95164b583', # 创建应用的 App Secret
'grant_type': 'authorization_code', # 文档 写死
'redirect_uri': 'http://127.0.0.1:8080/course_index', # 回调地址
'code': code # 接收到的编码
}
# 构造 post 对 weibo 的 url 发起请求
res = requests.post(url=url, data=data).text`在这里插入代码片`
print('<206>Token 换取的结果:', res)
# 得到请求转换为 字典 然后 取 键
return json.loads(res)['access_token']
因为要换取的东西有多个,accesstoken userinfo 等 所以 定义对应的请求方法,然后在 类方法调用 就简单很多了。
def get_weibo_accesstoken(code):, post 携带参数去请求,res 转成文本 取出 取出access_token 返回。
拿到 access_token 参数请求微博,他会返回我们 uid ,这个 uid 是 用户的唯一标识符。每次用户 扫码 发送的 uid 都是固定的,写一张表建立一个这样的字段然后保存他。
同时再去用刚才微博返回过来的 accesstoken 请求微博换取token
# 查询 Access_token 的相关信息 (获取 weibo 唯一标识符 uid)
def get_weibo_userinfo(access_token):
url = 'https://api.weibo.com/oauth2/get_token_info'
data = {
'access_token': access_token,
}
res = requests.post(url=url, data=data).text
print('<218>Access 的相关信息:', res)
return json.loads(res)['uid']
# 接收 微博回调页面 发送的 code
class Get_WeiBo_Code(APIView):
def post(self, request):
code = request.data['code']
print(code)
# 通过 code 获取授权的 access_token
access_token = get_weibo_accesstoken(code)
uid = get_weibo_userinfo(access_token)
# models.py
# 第三方平台登陆标识 表
class Social(models.Model):
# 这里说一下 uid 是 每个平台都会 拥有的 是为了标明用户的身份
uid = models.CharField(max_length=100, verbose_name='uid')
user = models.ForeignKey('User', on_delete=models.CASCADE)
THIRD_PARTY_CHOICE = {
(1, 'QQ'),
(2, 'WX'),
(3, 'WB'),
}
third_party = models.IntegerField(choices=THIRD_PARTY_CHOICE)
def __str__(self):
return self.user.name
创建好 表后 迁移。
# terminal
python manage.py makemigrations
python manage.py migrate
判断 用户之前 是否绑定过 微博,绑定过 就直接登录,没绑定过 重新 绑定一下。
class Get_WeiBo_Code(APIView):
def post(self, request):
code = request.data['code']
print(code)
# 通过 code 获取授权的 access_token
access_token = get_weibo_accesstoken(code)
uid = get_weibo_userinfo(access_token)
# 从数据库 取 数据判断 用户是否 注册过
try:
s = models.Social.objects.get(
third_party=3, # 直接绑定微博
uid=uid
)
except:
# 当 抛出异常就代表没有(微博用户)
# 给出对应的 数据
return Response({
'code': '10030',
'message': '用户不存在,请绑定本站',
'uid': uid
})
else:
# 没有 异常 代表曾经注册过
# 生成 token 保存登录状态
data = {
'id': s.user.id,
'email': s.user.email
}
jwt_token = create_JWT_(data)
# 发送到前台
return Response({
'code': 200,
'message': '您是本站的老用户',
'token': jwt_token,
'email': s.user.email
})
补充 这个 jwt 是我 给用户加密的方法 自己生成的 伪随机数。
# 生成 JWT 加密
def create_JWT_(data):
jwt_ = Risk_Serializer(SECRET_KEY, JWT_EXPIRE)
return jwt_.dumps(data).decode()
# 解除 JWT 加密
def remove_JWT_(jwt_):
try:
jwt_ = Risk_Serializer(SECRET_KEY, JWT_EXPIRE)
except SignatureExpired:
return None
return jwt_.loads(jwt_)
写完 逻辑之后 要给 前台 一个响应了。
axios({
'url': 'api/user/get_weibo_code/',
'method': 'post',
'data': form_data
}).then((res)=>{
// 判断用户是否 登陆成功, 如果成功 保持用户的 token 状态,然后直接 跳转到 首页(在后台 批判断过是否 绑定过 微博)
if(res.data.code == 200){
var token = res.data.token
window.localStorage.setItem('token', token)
this.$router.push({
name : 'course_index'
})
}else {
// 如没成功 就代表着 没 绑定过微博。跳转 然后携带我们的 唯一标识
this.message = res.data.message
this.$router.push({
name: 'bind_weibo',
query: {'uid': res.data.uid}
})
}
})
// 绑定微博的页面
<template>
<div id="bind_weibo">
<form @submit.prevent="register_">
<input type="email" v-model="register_email" @blur="check_email" class="form-control" placeholder="请输入邮箱">
<input type="password" v-model="register_pwd" class="form-control" placeholder="请输入密码">
</form>
<button @click="bind_weibo">绑定</button>
<h3>{{ message }}</h3>
</div>
</template>
定义点击事件,请求接口。
<script>
import axios from 'axios'
export default {
name: "bind_weibo",
data() {
return {
register_email: '',
register_pwd: '',
Can_be_bound: false,
message: ''
}
},
methods: {
check_email() {
var form_data = new FormData()
form_data.append('email', this.register_email)
axios({
'url': 'api/user/check_email/',
'method': 'post',
'data': form_data
}).then((res) => {
if (res.data.code == 200) {
this.Can_be_bound = true
}
this.message = res.data.message
})
},
很简单吧,请求个接口,并同时判断 密码长度是否 足够长。看着代码很臃肿,多 且 乱 一步一步看 都是简单的。我们 用到了 @blur。
@blur 是什么?
@blur 是当元素失去焦点时所触发的事件
当页面失去焦点的时候,触发 验证一下 邮箱是否可以被使用
# 检查邮箱是否被使用 过
class Check_email(APIView):
def post(self, request):
email = request.data['email']
try:
models.User.objects.get(email=email)
except:
return Response({
'code': 200,
'message': '邮箱可以被使用'
})
else:
return Response({
'code': 10200,
'message': '邮箱被占用'
})
点击绑定微博 触发的事件,
bind_weibo() {
if (!this.Can_be_bound) {
this.message = '邮箱不可以被绑定'
} else {
var register_pwd = this.register_pwd.length
console.log(register_pwd)
if (register_pwd < 6) {
this.message = '邮箱密码不得小于7位'
} else {
var form_data = new FormData()
form_data.append('email', this.register_email)
form_data.append('pwd', this.register_pwd)
form_data.append('uid', this.$route.query.uid);
axios({
'url': 'api/user/bind_weibo/',
'method': 'post',
'data': form_data
}).then((res) => {
if (res.data.code == 200) {
window.localStorage.setItem('token', res.data.token)
this.$router.push({
name: 'course_index'
})
}
})
}
}
},
mounted() {
this.uid = this.$route.query.uid
}
}
</script>
看注释
# 当是新用户的时候 绑定 邮箱
class Bind_weibo(APIView):
def post(self, request):
# 获取前台数据
email = request.data['email']
pwd = request.data['pwd']
uid = request.data['uid']
# 生成新的用户
user = models.User.objects.create(
email=email,
pwd=pwd
)
# 由接口 获取 判断是 weibo 的用户
data = {
'third_party': 3,
'uid': uid,
}
# 反序列化 数据 存入 Social 表
s = SocialSerializer(data=data, context={'user': user})
if s.is_valid():
s.save()
# 生成 需要加密的数据
data = {
'id': user.id,
'email': user.email
}
# 加密 发送到前台 保存登录状态
jwt_token = create_JWT_(data)
return Response({
'code': 200,
'token': jwt_token,
'email': user.email
})
else:
return Response({
'code': 10300,
'message': '数据填写不完整'
})
# 序列化器
class SocialSerializer(Serializer):
uid = serializers.CharField(max_length=190)
third_party = serializers.IntegerField()
def create(self, data):
print(self.context)
s = models.Social.objects.create(
user=self.context['user'],
**data
)
return s
呼 这样的话 就都完成了 收工。
更多推荐
所有评论(0)