首先进去新浪微博开放平台注册应用
点击其他进入
点击创建
微博会给你 App Key和App Secret,这两个要保存下来
点击左侧高级信息,然后进去点击编辑
这时会让你自己设置回调路由和取消授权的路由,回调路由是当你用第三方登录时,微博会给你返回 一个code,这个code会返回到这个路由上,这个路由是vue路由,也就是一个vue前端页面
将回调路由保存下来(这里只用到了回调路由)
好啦,现在准备工作已经做好了,开始做咯
先给大家看一幅流程图
流程大概是这样
token,username,user_id保存的位置
下面该实现代码了
用户表就不说啦,上面说到设计到三方登录,需要一个第三方社交表关联用户表
# 第三方社交表
class SocialUser(models.Model):
# 这个字段是关联用户表的外键
user = models.ForeignKey(Users,on_delete=models.CASCADE,verbose_name='用户',related_name='user_info')
# 这个不是个字段,属于二元组,1就代表的PC,真正入库的是 int
platfrom_type_choices = (
(1,'PC'),
(2,'Androia'),
(3,'IOS'),
)
platfrom_id = models.IntegerField(max_length=1,choices=platfrom_type_choices,verbose_name='平台类型')
platfrom_choices = (
(1,'QQ'),
(2,'微博'),
(3,'微信'),
)
platfrom_type = models.IntegerField(max_length=1,choices=platfrom_choices,verbose_name='社交平台')
uid = models.CharField(max_length=100,verbose_name='用户社交id')
class Meta:
db_table = 'socialuser'
verbose_name_plural = '用户社交表'
数据库迁移:
python manage.py makemigrations
python manage.py migrate
把微博返回的几个参数配置到settings里
# 配置微博返回的参数
WEIBO_APP_KEY = '3312233733'
WEIBO_APP_SECRET = 'c88e0c5e4abe66e89f48897ddef4be3a'
WEIBO_CALL_BACK = 'http://127.0.0.1:8080/#/come_back' # 回调路由
vue微博登录链接是向后台获取的
url先给个默认值为空
利用钩子函数向后台获取微博登录页链接
// 获取第三方登录链接
mounted() {
this.axios({
method: "get", // 以post方式访问接口
url: "http://127.0.0.1:8000/api/get_weibo_login/",
}).then(res=>{
// 给微博链接赋值
this.weibo_login_url = res.data.weibo_url
}).catch(error=>{
console.log(error)
})
},
后台拼接微博登录链接
# 拼接微博登录页面链接返回前端
class Get_weibo_login(APIView):
'''
微博的登陆页面地址:https://api.weibo.com/oauth2/authorize?
链接需要携带三个参数,是我们注册应用时微博给的参数还有一回调地址
我们在settings配置好,哪里用哪里取
client_id = 4152203033
reponse_type=code
redirect_uri=http://127.0.0.1:8000/api/weibo_back/
'''
def get(self,request):
url = 'https://api.weibo.com/oauth2/authorize?'
data = {'client_id':WEIBO_APP_KEY,'reponse_type':'code','redirect_uri':WEIBO_CALL_BACK}
weibo_url = url + urlencode(data) # urlencode 能将dict 解析成路由拼接
return Response({'weibo_url':weibo_url})
用户点击微博登录,微博将 code 返回到回调路由上,创建vue回调页面
页面将携带 code 访问后台获取响应
跳转中...
后台代码
创建token
from rest_framework_jwt.settings import api_settings
# 创建payload的函数 载荷
jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
# 创建 token 函数
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
# 获取vue 传来的code 向微博获取 uid,access_token
class Get_weibo_uid(APIView):
'''
这次访问微博是获取 uid,access_token
url = https://api.weibo.com/oauth2/access_token?
连接需要拼接一些必要的参数方便微博认证
'''
def get(self,request):
code = request.query_params.get('code')
url = 'https://api.weibo.com/oauth2/access_token?'
data = {
'client_id':WEIBO_APP_KEY,
'client_secret':WEIBO_APP_SECRET,
'grant_type': 'authorization_code',
'code':code,
'redirect_uri':WEIBO_CALL_BACK
}
# 这次是发起的 post 请求 返回的响应是json字符串,需要解析取值
response = json.loads(requests.post(url,data).text)
'''
这是返回的 response 数据
{'access_token': '2.00jqYNTGfgNAXEbd85e6c672uTGF8E',
'remind_in': '157679999', 'expires_in': 157679999,
'uid': '5928542965', 'isRealName': 'true'}
'''
uid = response.get('uid')
if not uid:
# 如果没有返回 uid 证明第三方授权失败
data = {'code':202,'mes':'三方授权失败'}
else:
'''
有uid的话就拿uid去三方社交表去查表里有没有这个uid,如果有就可以直接返回token登录,没有就需要前端引导用户去绑定自己的信息
'''
try:
socialuser = models.SocialUser.objects.get(uid=uid)
# 将查询出来的 socialuser 生成载荷 创建 token
payload = jwt_payload_handler(socialuser.user) # 创建载荷
token = jwt_encode_handler(payload) # 创建 token
data = {'code':200,'token':token,'username':socialuser.user.username,'user_id':socialuser.user.id}
except:
'''
将response返回前端,前端保存access_token,uid再通过后台访问微博获取用户信息入库
'''
data = {'code':201,'mes':json.dumps(response)}
return Response(data)
上面说到有两种情况,社交表里有 uid 和没有 uid,有uid 的直接返回 token 前端保存登录成功,没有 uid 前端就该跳到用户绑定页面
vue绑定页面代码
后台代码
# 拿到前端的 access_token,uid向微博获取用户信息 入库返回前端 token/
class Bind_user(APIView):
def post(self,request):
from django.http import QueryDict
username = request.data['username']
password = request.data['password']
password2 = request.data['password2']
try:
access_token_object = json.loads(request.data.get('access_token_object'))
except:
return Response({'code':201,'mes':'没有第三方认证'})
if not all([username,password,access_token_object]):
mes = {'code':201,'mes':'输入不能为空'}
return Response(mes)
else:
# 拼接访问微博获取用户基本信息链接
get_user_url = "https://api.weibo.com/2/users/show.json?access_token=%s&uid=%s"%(
access_token_object['access_token'],access_token_object['uid']
)
# 获取到了用户信息 准备入库
data = requests.get(url=get_user_url).text
data_user = {'username':username,'password':password,'password2':password2,'email':'***@qq.com','mobile':'***'}
# 反序列化器只接收 QueryDict 对象,这里转了类型
queryDict_user = QueryDict('', mutable=True)
queryDict_user.update(data_user)
try:
with transaction.atomic():
# 其实可以入库了,这里多事了,用了反序列化器
user = serializer.userSerializer(data=queryDict_user)
if user.is_valid():
user.save()
users = models.Users.objects.filter(username=username).first()
data_socialuser = {'platfrom_id':1,'platfrom_type':2,'uid':access_token_object['uid']}
queryDict_socialuser = QueryDict('', mutable=True)
queryDict_socialuser.update(data_socialuser)
# 涉及到外键就要把对象传过去反序列器接受
socialuser = serializer.socialuserSerializer(data=queryDict_socialuser,context={'outer_key':users})
if socialuser.is_valid():
socialuser.save()
payload = jwt_payload_handler(users) # 创建载荷
token = jwt_encode_handler(payload) # 创建 token
mes = {'token':token,'username':users.username,'user_id':users.id}
return Response(mes)
except:
return Response('授权失败')
这里用反序列化器入库,要在 serialializer.py 里创建反序列化器
# 用户社交表 反序列化器
class socialuserSerializer(serializers.Serializer):
# 要入什么字段就在这里写什么字段,字段名一定要和表里的一致
platfrom_id = serializers.IntegerField()
platfrom_type = serializers.IntegerField()
uid = serializers.CharField()
class Meta:
fields = "__all__"
model = models.SocialUser # 指定的表
related_name='user_info'
def create(self,validated_data):
# 这个表关联着用户的外键, user:是社交表的外键字段 self.context['outer_key']:views传过来 的users对象
users = models.SocialUser.objects.create(user=self.context['outer_key'],**validated_data) # 创建用户
return users
下面这些就是微博返回的 用户基本信息,自己也可以打印出来看看
‘’’
{“id”:6211711885,“idstr”:“6211711885”,“class”:1,“screen_name”:“用户6211711885”,“name”:“用户6211711885”,“province”:“100”,“city”:“1000”,“location”:“其他”,“description”:"",“url”:"",“profile_image_url”:“http://tvax2.sinaimg.cn/default/images/default_avatar_male_50.gif",“cover_image_phone”:“http://ww1.sinaimg.cn/crop.0.0.640.640.640/549d0121tw1egm1kjly3jj20hs0hsq4f.jpg”,“profile_url”:“u/6211711885”,“domain”:"",“weihao”:"",“gender”:“m”,“followers_count”:1,“friends_count”:1,“pagefriends_count”:0,“statuses_count”:0,“video_status_count”:0,“favourites_count”:0,“created_at”:"Sun Apr 23 20:46:07 +0800 2017”,“following”:false,“allow_all_act_msg”:false,“geo_enabled”:true,“verified”:false,“verified_type”:-1,“remark”:"",“insecurity”:{“sexual_content”:false},“ptype”:0,“allow_all_comment”:true,“avatar_large”:“http://tvax2.sinaimg.cn/default/images/default_avatar_male_180.gif",“avatar_hd”:“http://tvax2.sinaimg.cn/default/images/default_avatar_male_180.gif”,“verified_reason”:"",“verified_trade”:"",“verified_reason_url”:"",“verified_source”:"",“verified_source_url”:"",“follow_me”:false,“like”:false,“like_me”:false,“online_status”:0,“bi_followers_count”:0,“lang”:“zh-cn”,“star”:0,“mbtype”:0,“mbrank”:0,“block_word”:0,“block_app”:0,“credit_score”:80,“user_ability”:0,“urank”:0,“story_read_state”:-1,“vclub_member”:0,“is_teenager”:0,“is_guardian”:0,"is_teenager_list”:0}
‘’’
终于写完了,太麻烦了