vue&django微博第三方登录

首先进去新浪微博开放平台注册应用
在这里插入图片描述
点击其他进入
在这里插入图片描述
点击创建
在这里插入图片描述
微博会给你 App Key和App Secret,这两个要保存下来
在这里插入图片描述
点击左侧高级信息,然后进去点击编辑
在这里插入图片描述
这时会让你自己设置回调路由和取消授权的路由,回调路由是当你用第三方登录时,微博会给你返回 一个code,这个code会返回到这个路由上,这个路由是vue路由,也就是一个vue前端页面
将回调路由保存下来(这里只用到了回调路由)
好啦,现在准备工作已经做好了,开始做咯
先给大家看一幅流程图第三方登录流程图
流程大概是这样

  1. 客户端访问微博登录页面,微博认证成功会将 code 返回给回调页面
  2. 回调页面拿着 code 访问后台
  3. 后台将 App Key,App Secret,回调路由,code封装好,发起获取uid的post请求时一起将这些参数带去
  4. 微博会将 uid和access_token返回给后台,后台用uid去三方社交表查询是否有这个uid,有就代表以前登录过,直接创建token,username,user_id返回给回调页,如果表里没有uid,说明第一次登录就先将uid和access_token返回给回调页
  5. 回调页以200状态判定返回的是token等参数,将token等数据保存,跳首页面,登录成功。
  6. 回调页判定返回的是uid,access_token,这时其实用户是被第三方认证过的,我们需要在自己本地数据库保存用户基本信息,所以讲uid等参数保存浏览器跳到用户绑定页面。
  7. 用户绑定页面携带uid,access_token再次访问后台,后台带着这些参数访问微博获取用户基本信息
  8. 得到相应,后台将用户基本信息入库用户表,用户社交表,然后生成token,username,user_id返回绑定页面,绑定页面将token等数据保存到浏览器跳首页,登录成功

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 访问后台获取响应

<template>
    <div id="come_back">
        <p>跳转中...</p>
    </div>
</template>
<script>
// document.title = "跳转页面";
export default {
    // 从url上拿到 code 去后台获取token
    mounted() {
        var r = this.$router
        let code = this.$route.query.code
        this.axios({
            url:'http://127.0.0.1:8000/api/get_weibo_uid/?code='+code,
            method:'get'
        }).then(res=>{
        	// 200就将 token 保存登录成功
            if(res.data.code==200){
                console.log(res.data)
                localStorage.clear() // 清空本地存储区域
                sessionStorage.clear() // 清空session区域
                localStorage.username = res.data.username
                localStorage.token = res.data.token
                localStorage.user_id = res.data.user_id
                r.push({'path':"/"})
            }else if(res.data.code==202){
                console.log(res.data.mes)
            }else{
            	// 将uid,access_token等整体对象保存,跳转用户绑定页
                localStorage.access_token_object = res.data.mes
                r.push({'path':"/userbind"})
            }
        }).catch(error=>{
            console.log(error)
        })
    },
}
</script>

后台代码

创建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绑定页面代码

<script>
export default {
   
    methods: {
        on_submit:function(){
         
                var r = this.$router
                let access_token_object =  localStorage.access_token_object
                let data = new FormData()
                data.append('username',this.user_name)
                data.append('password',this.user_pwd)
                data.append('password2',this.user_pwd_again)
                data.append('access_token_object',access_token_object)
                this.axios({
                    url:'http://127.0.0.1:8000/api/bind_user/',
                    method:'post',
                    data:data
                }).then(res=>{
                    if(res.data.code==201){
                        alert(res.data.mes)
                    }else{
                    	// 将返回的 token,username,user_id保存,登录成功
                        console.log(res.data)
                        localStorage.clear() // 清空本地存储区域
                        sessionStorage.clear() // 清空session区域
                        localStorage.username = res.data.username
                        localStorage.token = res.data.token
                        localStorage.user_id = res.data.user_id
                        r.push({'path':"/"})
                    }

                }).catch(error=>{
                    console.log(error)
                })
        },
    },

}
</script>

后台代码

# 拿到前端的 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}
‘’’

终于写完了,太麻烦了

猜你喜欢

转载自blog.csdn.net/SJK__/article/details/90737753
今日推荐