vue实现第三方登录——qq

目录

一、介绍

如何申请QQ登录

 解决点击登录后打开一个新窗口

 二、vue项目中使用

(1)引入使用

(2)自动生成的代码转换a链接跳转  

(3)将测试地址映射到本地

三、登陆后的三条路线

第一条路线

第二条路线

第三条路线


一、介绍

整体流程

  • 在登录页面,QQ登录图片处,赋予其打开QQ登录页面功能。

  • 回跳的页面得到QQ给的唯一标识openId,根据openId去后台查询是否已经绑定过账户。

    • 如果绑定过,完成登录。

    • 没有绑定过

      • 有账号的,绑定手机号,即为登录。

      • 没账号的,完善账户信息,即为登录。

  • 登录成功后,跳转首页,或者来源页面。

如何申请QQ登录

参考文档:

  1. 自己要有一个已备案的,本身具有登录功能的网站。网站需要有QQ登录的逻辑(登录页面,回跳页面)。

  2. 在QQ互联上进行身份认证,审核通过。

  3. 在QQ互联上创建应用,填入自己网站的域名,备案号,回调地址。等待审核。

  4. 审核通过后,会给出:应用ID,应用key 回调地址。

以上四个步骤,一般由后端或运维完成,才能完成QQ登录

测试

这里已有测试使用的appid和uri (是通过了QQ官方认证)

# appid			  :10055xxxx
# redirect_uri :http://www.corho.com:8080/#/login/callback

在申请QQ登录功能成功之后,我们就可以使用qq提供的SDK工具来完成登录相关功能。  

 普通项目使用

<script src="http://connect.qq.com/qc_jssdk.js" data-appid="xxxx" data-redirecturi="http://www.corho.com:8080/#/login/callback"></script>

<span id="qqLoginBtn"></span>

<script>
    QC.Login({
         btnId: 'qqLoginBtn'
    })
</script>

通过 QC.Login 就可以自动在页面上生成一个qq登录图标 点击后也可以跳转  但是看到效果也无法跳到指定页面

 解决点击登录后打开一个新窗口

 通过生成的代码是一个a标签包着一个img  我们只需要把链接整体拿过来  把window.open 之类的删掉  只有a链接的herf跳转

<a href="https://graph.qq.com/oauth2.0/authorize?client_id=xxx;response_type=token&amp;scope=all&amp;redirect_uri=http%3A%2F%2Fwww.corho.com%3A8080%2F%23%2Flogin%2Fcallback">
    <img src="https://qzonestyle.gtimg.cn/qzone/vas/opensns/res/img/Connect_logo_7.png" alt="QQ登录" border="0">
</a>

 二、vue项目中使用

(1)引入使用

因为多个组件可能都要使用qq登录 如果直接引在每个组件很繁琐  所以直接引入在piublic/index.html中  等价于 npm  i  qc

填写的data-appid和redirecturi是本项目申请的测试账号和密码

<script src="http://connect.qq.com/qc_jssdk.js" data-appid="xxx" data-redirecturi="http://www.corho.com:8080/#/login/callback"></script>

在组件中使用

import QC from 'qc' 
<span id="qqLoginBtn"></span>
onMounted(() => {
   // 组件渲染完毕,使用QC生成QQ登录按钮
   QC.Login({
     btnId: 'qqLoginBtn'
   })
 })

 如果不做此步qc 是去找node_modules去找但是 并没有npm i 会报错

  //  这个是设置外部扩展,模块为qc变量名为QC,导入qc将不做打包。
  configureWebpack: {
    externals: {
      qc: 'QC'
    }
  },

告诉wepback,QC 是外部拓展:

  1. 如果遇到 import 'qc' 不要去node_modules下找了。

  2. npm run build时,也不要去打包 qc。

(2)自动生成的代码转换a链接跳转  

拿到调试工具中的a链接后把上面写的全删了  前提是有申请后的 id

     <a href="https://graph.qq.com/oauth2.0/authorize?client_id=xxxxx&amp;response_type=token&amp;scope=all&amp;redirect_uri=http%3A%2F%2Fwww.corho.com%3A8080%2F%23%2Flogin%2Fcallback"><img src="https://qzonestyle.gtimg.cn/qzone/vas/opensns/res/img/Connect_logo_7.png" alt="QQ登录" border="0"></a>

(3)将测试地址映射到本地

登录之后的回调页面是http://www.corho.com:8080/#/login/callback 这个地址不是localhost打头的 ,并不是我们的本地地址

修改host

由于域名是www.corho.com和localhost不一致无法回调页面,需要在本地修改hosts地址。

 windows

1. 找到 C:\Windows\System32\drivers\etc 下hosts文件
2. 在文件末尾中加入一行  127.0.0.1       www.corho.com
3. 保存即可。
# 如果提示没有权限
1. 将hosts文件移到桌面,然后进行修改,确认保存。
2. 将桌面hosts文件替换c盘文件

 mac OS

1. 打开命令行窗口
2. 输入:sudo vim /etc/hosts
3. 按下:i 键
4. 输入:127.0.0.1       www.corho.com
5. 按下:esc
6. 按下:shift + :
7. 输入:wq 回车即可

需要开启webpack服务器权限

IP或域名访问

在vue.config.js中

// 这个是给webpack-dev-server开启可IP和域名访问权限。
chainWebpack: config => {
  config.devServer.disableHostCheck(true)
}

重启后,这时候再去尝试登录后就会调到  本地地址 但是本地地址没有设置路由 所以显示的是空页面

配置路由

 { path: '/login/callback', component: () => import('@/views/login/callback.vue') }

接下俩就可以去 指定的路由组件中去做操作

三、登陆后的三条路线

  • 已注册,已绑定 ---> 登录成功,跳转首页,或者来源页面

  • 已注册,未绑定,绑定手机号 ----> 登录成功,跳转首页,或者来源页面

  • 未注册,补充完善账户信息 ----->登录成功,跳转首页,或者来源页面

背景知识

检查是否登录

QC.Login.check() :返回true|false, 用来检查是否登录

获取登录凭证Id

QC.Login.getMe(unionId=>{console.log(unionId)})

获取qq信息(头像 昵称)

QC.api('get_user_info').success(res=>console.log(res))

  1. 通过QQ的API(QC.Login.getMe)获取unionId

  2. 根据unionId去调用本项目的接口进行登录,如果成功,就代表已注册已绑定:

  3. 记录返回的用户信息

  4. 跳转页面。

第一条路线

拿qq返回的id调用本地接口

成功:返回的信息是用户信息,调用vuex中的actions保存信息  保存完之后跳转到主页

失败:在catch中原地不动 等待其他两条路线

<script>
import LoginHeader from './components/loginHeader.vue'
import LoginFooter from './components/loginFooter.vue'
import { ref } from 'vue'
import { userQQLogin } from '@/api/user'
import { useStore } from 'vuex'
import { useRouter } from 'vue-router'
import Message from '@/components/XtxMessage.vue'
import QC from 'qc'
import CallbackBind from './components/callbackBind.vue'
import CallbackPatch from './components/callbackPatch.vue'
export default {
  name: 'PageCallback',
  components: { LoginHeader, LoginFooter, CallbackBind, CallbackPatch },
  setup () {
    const unionId = ref(null)
    const store = useStore()
    const router = useRouter()
    QC.Login.check() && QC.Login.getMe(openId => {
      console.log(openId)
      unionId.value = openId
      userQQLogin(openId).then(data => {
        //   走到then说明成功
        // 1. 存储用户信息
        store.commit('user/setUser', data.result)
        // 跳转到主页
        router.push('/')
        // 弹框提示
        console.log(data)
        Message({ type: 'success', text: '登陆成功!' })
      }).catch(() => {
        //   走到catch说明失败 就留在此页面
        console.log('没有绑定 留此页面')
      })
    })
    const hasAccount = ref(true)
    return { hasAccount, unionId }
  }
}
</script>

第二条路线

已有账号 请绑定手机 :意思是已有当前项目的账号了 直接绑定手机号

路线:

获取验证码 :  1. 判断手机号校验是否正确 2.  调用获取验证码接口   

调用绑定接口: 1. 看用户名和验证码 表单校验是否正确 2.调用接口  3.提示文本 4.跳到主页

<script>
import { ref, reactive } from 'vue'
import QC from 'qc'
import { Form, Field } from 'vee-validate'
import { mobile, code } from '@/utils/validate'
import { useCountDown } from '@/compositions/index'
import { userQQBindCode } from '@/api/user'
import Message from '@/components/message'
import { useRouter } from 'vue-router'
import { useStore } from 'vuex'

export default {
  name: 'CallbackBind',
  components: {
    Form, Field
  },
  props: {
    unionId: {
      type: String,
      default: ''
    }
  },
  setup (props) {
    // 1. 定义数据项:qq头像 昵称
    const nickname = ref('')
    const avatar = ref('')
    QC.Login.check() && QC.api('get_user_info').success(res => {
      avatar.value = res.data.figureurl_2
      nickname.value = res.data.nickname
    }) // 获取当前登录的QQ账号的信息

    const target = ref(null)
    // 表单数据对象
    const formData = reactive({
      mobile: '13241051259',
      code: ''
    })
    // 校验规则
    const mySchema = {
      mobile: mobile,
      code: code
    }
    const store = useStore()
    const router = useRouter()
    const { start, time } = useCountDown()
    // 发送验证码倒计时
    const send = async () => {
      // 如果手机号格式不正确
      if (mobile(formData.mobile) !== true) {
        Message({ type: 'error', text: '手机号格式错误' })
        return
      }
      if (time >= 0) return
      try {
        await userQQBindCode(formData.mobile).then((res) => {
          Message({ type: 'success', text: '获取验证码成功!' })
          start(60)
        })
      } catch (error) {
        Message({ type: 'warn', text: error.response.data.message + ', 请稍后重试' || '获取验证码失败!' })
      }
    }

    // 开始绑定
    const binding = () => {
      console.log(props.unionId)
      target.value.validate().then((vilid) => {
        // 开始绑定
        if (vilid) doBingding()
      }
      ).catch(vlida => console.log(vlida))
    }
    const doBingding = async () => {
      try {
        await store.dispatch('user/userQQBindLogin', { unionId: props.unionId, mobile: formData.mobile, code: formData.code })
        Message({ type: 'success', text: '提交成功!' })
        router.push('/')
      } catch (error) {
        console.dir(error)
        Message({ type: 'error', text: error.message || '提交失败' })
      }
    }
    return { nickname, avatar, formData, target, mySchema, send, time, binding }
  }
}
</script>

第三条路线

 没有项目账号,也没有绑定手机号

路线:

首先校验用户名 调用接口 看当前用户名是否存在  

校验密码 两次密码是否相等

获取验证码 :  1. 判断手机号校验是否正确 2.  调用获取验证码接口   

调用绑定接口: 1. 所有表单校验是否正确 2.调用接口  3.提示文本 4.跳到主页

<script>
import { reactive, ref } from 'vue'
import { Form, Field } from 'vee-validate'
import { mobile, code, rePassword, password, accountApi as account } from '@/utils/validate'
import { useCountDown } from '@/compositions/index'
import Message from '@/components/message'
import { userQQPatchCode } from '@/api/user'
import { useRouter } from 'vue-router'
import { useStore } from 'vuex'
export default {
  name: 'CallbackPatch',
  components: {
    Form, Field
  },
  props: {
    unionId: {
      type: String,
      default: ''
    }
  },
  setup (props) {
    // 1. 表单校验 多两个校验:用户名是否存在,再次输入密码是否一致
    // 2. 发送短信验证码:接口API定义
    // 3. 完善信息

    // 表单数据对象
    const formData = reactive({
      account: null,
      mobile: null,
      code: null,
      password: null,
      rePassword: null
    })
    // 校验表单
    const mySchema = {
      account,
      mobile,
      code,
      password,
      rePassword
    }

    const { start, time } = useCountDown()
    // 发送验证码倒计时
    const send = async () => {
      // 如果手机号格式不正确
      if (mobile(formData.mobile) !== true) {
        Message({ type: 'error', text: '手机号格式错误' })
        return
      }
      if (time >= 0) return
      try {
        await userQQPatchCode(formData.mobile).then((res) => {
          Message({ type: 'success', text: '获取验证码成功!' })
          start(60)
        })
      } catch (error) {
        Message({ type: 'warn', text: error.response.data.message + ', 请稍后重试' || '获取验证码失败!' })
      }
    }

    // 开始绑定
    const target = ref(null)
    const store = useStore()
    const router = useRouter()

    // 立即提交
    const submit = () => {
      console.log(props.openId)
      target.value.validate().then((vilid) => {
        // 开始绑定
        if (vilid) doSubmit()
      }
      ).catch(vlida => console.log(vlida))
    }
    const doSubmit = async () => {
      try {
        await store.dispatch('user/userQQPatchLogin', {
          unionId: props.unionId,
          mobile: formData.mobile,
          code: formData.code,
          account: formData.account,
          password: formData.password
        })
        Message({ type: 'success', text: '提交成功!' })
        router.push('/')
      } catch (error) {
        console.dir(error)
        Message({ type: 'error', text: error.message || '提交失败' })
      }
    }
    return { formData, mySchema, send, time, submit, target }
  }
}
</script>

猜你喜欢

转载自blog.csdn.net/m0_46846526/article/details/119243300#comments_26392827