手把手云开发小程序-(三)_uniclould小程序的登录

一,微信程序的登录流程概述

其实uniclould有uni-id来实现登录的一系列逻辑,但是它太多对我而言无用的数据了.我只需要简单的数据.那就自己写呗.

微信官网已经把登录的流程写得很清楚了,官网地址:小程序登录 | 微信开放文档 (qq.com)

1.jpg

首先小程序通过wx.login()获取登录凭证code,每次调用code均不同,有效时间是5分钟,该code被微信接口服务验证一次就会失效了,小程序获取到code之后,通过wx.request()将code发送到开发者服务器,开发者服务器将appid,appSecret(密钥),和code发送给微信接口服务去校验登录凭证,成功会返回session_key(会话信息记录)和openid(用户唯一标识),用户登录成功后,开发者服务器可以将openid和session_key保存,生成一个自定义登录态的token(令牌)响应回去给小程序,通过token可以查询openid和session_key,小程序下次请求只要携带着token就可以证明已经登录。

接下来,我会照着这个流程,一步步完成小程序的免登.

二,获取code

按照官网的wx.login就可以获得这个code.

官网地址:https://developers.weixin.qq.com/miniprogram/dev/api/open-api/login/wx.login.html

具体的使用如下:直接在项目根目录的app.vue文件中写就行:

<script>
  export default {
    onLaunch: function() {
      console.log('App Launch')
      const token=uni.getStorageSync('token')
      if(!token){
        wx.login({
          success (res) {
            if (res.code) {
              //发起网络请求
              console.log("----",res.code)
            } else {
              console.log('登录失败!' + res.errMsg)
            }
          }
        })
      }
    },
    onShow: function() {
      console.log('App Show')
    },
    onHide: function() {
      console.log('App Hide')
    }
  }
</script><style>
  /*每个页面公共css */
</style>

然后在微信开发者工具中重新编译,查看控制台,就可以看到打印出来的code了.

---- 0f3Exu100SIhmQ12w3300wK26o3Exu11

三,新建接口接收这个code

现在我们已经获取到这个code了,接下来需要将code传递给我们的服务器.

于是我们首先需要新建这个服务端接口提前端调用.

3.1,新建login接口

依旧是使用云对象的方式,右键云服务器的云对象文件夹,新建云对象:

2.png

然后书写如下代码:

  myLogin(param) {
    // 参数校验,如无参数则不需要
    if (!param) {
      return {
        errCode: 'PARAM_IS_NULL',
        errMsg: 'code不能为空'
      }
    }
    // 业务逻辑
    console.log("-------",param)
    // 返回结果
    return {
      param1 //请根据实际需要返回值
    }
  }

四,前端调用登录接口传递code

现在我们已经具备了后端登录接口,就需要在前端调用,将code传递给后端.

于是在刚刚app.vue文件中继续书写如下代码:

<script>
  export default {
    onLaunch: async function() {
      console.log('App Launch')
      const token=uni.getStorageSync('token')
      
      if(!token){
        console.log("233333")
        wx.login({
          async success (res) {
            let result=res
            if (result.code) {
              //发起网络请求
              let params={
                code:result.code
              }
              const myLogin = uniCloud.importObject('login') // 导入云对象
              const res = await myLogin.myLogin(params)
              console.log("----",res)
            } else {
              console.log('登录失败!' + res.errMsg)
            }
            }
        })
      }
    },
    onShow: function() {
      console.log('App Show')
    },
    onHide: function() {
      console.log('App Hide')
    }
  }
</script><style>
  /*每个页面公共css */
</style>

通过这一步我们将code通过云对象(也就是我们常规前后端开发中的接口)的形式传递给了我们的服务器(云后台).

五,后端接收到code,调用微信接口

这里我们后端已经接收到code,按照文档,需要接着把code、appid、appsecret通过调用jscode2session接口来获取sessionKey和openId.

参考的官网地址:小程序登录 | 微信开放文档 (qq.com)

于是参照文档,我们在login云对象中书写如下代码:

// 云对象教程: https://uniapp.dcloud.net.cn/uniCloud/cloud-obj
// jsdoc语法提示教程:https://ask.dcloud.net.cn/docs/#//ask.dcloud.net.cn/article/129
const createConfig = require('uni-config-center')
const shareConfig = createConfig({ // 获取配置实例
    pluginId: 'share-config' // 上文我们在common/uni-config-center下的插件配置目录名
})
const config = shareConfig.config() // 获取common/uni-config-center/share-config/config.json的内容
module.exports = {
  _before: function () { // 通用预处理器},
  /**
   * myLogin方法描述
   * @param {string} param 参数1描述
   * @returns {object} 返回值描述
   */
  async myLogin(param) {
    // 参数校验,如无参数则不需要
    if (!param) {
      return {
        errCode: 'PARAM_IS_NULL',
        errMsg: 'code不能为空'
      }
    }
    // 业务逻辑
    const URL = `https://api.weixin.qq.com/sns/jscode2session?appid=${config.appid}&secret=${config.secret}&js_code=${param.code}&grant_type=authorization_code`
    const requestOptions = {
      method: 'GET',
      dataType: 'json'
    }
    const res1 = await uniCloud.httpclient.request(URL,requestOptions)
    if(res1.status==200){
      return res1.data
    }else{
      return {
        code:10001,
        msg:'从微信获取session_id失败'
      }
    }
  }
}

值得注意的是,这里我把appid和存储在了上一篇文章中说到的config.json中.

于是,这里我们在服务端调用微信接口,获取到了sessionKey和openId.

六,根据sessionKey和openId生成自定义的登录态

现在获取到sessionKey和openId,因为不建议直接暴露这两个参数给客户端,所以我们通常会利用这两个参数生成自己定义的登录态.

6.1,封装加解密方法

一般我们需要进行加密,考虑到大部分接口都需要进行加解密,于是可以在common中新建一个公共文件夹(右键common新建文件夹即可):common-boject,然后在该文件夹下安装加解密依赖:

new_3.png

npm install crypto-js

然后common下新建index.js文件,对加解密方法进行封装处理:

const CryptoJS = require("crypto-js");
// 十六位十六进制数作为密钥
const SECRET_KEY = CryptoJS.enc.Utf8.parse("1234567890123456");
// 十六位十六进制数作为密钥偏移量
const SECRET_IV = CryptoJS.enc.Utf8.parse("1234567890123456");
module.exports ={
  //加密
  encrypt (data) {
    if (typeof data === "object") {
      try {
        // eslint-disable-next-line no-param-reassign
        data = JSON.stringify(data);
      } catch (error) {
        console.log("encrypt error:", error);
      }
    }
    const dataHex = CryptoJS.enc.Utf8.parse(data);
    const encrypted = CryptoJS.AES.encrypt(dataHex, SECRET_KEY, {
      iv: SECRET_IV,
      mode: CryptoJS.mode.CBC,
      padding: CryptoJS.pad.Pkcs7
    });
    return encrypted.ciphertext.toString();
  },
  //解密
  decrypt (data) {
    const encryptedHexStr = CryptoJS.enc.Hex.parse(data);
    const str = CryptoJS.enc.Base64.stringify(encryptedHexStr);
    const decrypt = CryptoJS.AES.decrypt(str, SECRET_KEY, {
      iv: SECRET_IV,
      mode: CryptoJS.mode.CBC,
      padding: CryptoJS.pad.Pkcs7
    });
    const decryptedStr = decrypt.toString(CryptoJS.enc.Utf8);
    return decryptedStr.toString();
  }
}
6.2,在login云对象中引入加解密方法

在login云对象上右键-管理公共模块或扩展库依赖,勾选上文创建好的common库.

new-3-1.png

然后修改login云对象:

// 云对象教程: https://uniapp.dcloud.net.cn/uniCloud/cloud-obj
// jsdoc语法提示教程:https://ask.dcloud.net.cn/docs/#//ask.dcloud.net.cn/article/129
​
const createConfig = require('uni-config-center')
const shareConfig = createConfig({ // 获取配置实例
    pluginId: 'share-config' // 上文我们在common/uni-config-center下的插件配置目录名
})
const config = shareConfig.config() // 获取common/uni-config-center/share-config/config.json的内容
+ const {encrypt,decrypt} =require("common-object");
​
module.exports = {
  _before: function () { // 通用预处理器
  },
  /**
   * myLogin方法描述
   * @param {string} param 参数1描述
   * @returns {object} 返回值描述
   */
  async myLogin(param) {
    // 参数校验,如无参数则不需要
    
    if (!param) {
      return {
        errCode: 'PARAM_IS_NULL',
        errMsg: 'code不能为空'
      }
    }
    // 业务逻辑
    const URL = `https://api.weixin.qq.com/sns/jscode2session?appid=${config.appid}&secret=${config.secret}&js_code=${param.code}&grant_type=authorization_code`
    const requestOptions = {
      method: 'GET',
      dataType: 'json'
    }
    const res1 = await uniCloud.httpclient.request(URL,requestOptions)
    if(res1.status==200){
+     const token=encrypt(JSON.stringify(res1.data))
+     const userList=await checkOpenID(res1.data.openid)
+     if(userList.length>=1){
+       //在user表中更新token,返回新token
+       return {
+         code:10000,
+         msg:'登录成功',
+         token:token,
+         id:userList[0]._id
+       }
+     }else{
+       //注册用户
+       const registerInfo=await register(res1.data.openid)
+       //返回token
+       return {
+         code:10001,
+         msg:'注册并登录成功',
+         token:token,
+         id:registerInfo[0]._id
+       }
+     }
    }else{
      return {
        code:10001,
        msg:'从微信获取session_id失败'
      }
    }
  }
}

七,新建用户数据表,根据openId查询数据表

在控制台新建user数据表:

3.png

然后在login云对象中新建注册用户的方法:获取该数据表,查询是否已存在用户,不存在则新增用户.

于是完整的login云对象变成:

// 云对象教程: https://uniapp.dcloud.net.cn/uniCloud/cloud-obj
// jsdoc语法提示教程:https://ask.dcloud.net.cn/docs/#//ask.dcloud.net.cn/article/129const createConfig = require('uni-config-center')
const shareConfig = createConfig({ // 获取配置实例
    pluginId: 'share-config' // 上文我们在common/uni-config-center下的插件配置目录名
})
const config = shareConfig.config() // 获取common/uni-config-center/share-config/config.json的内容
const {encrypt,decrypt} =require("common-object");
const db = uniCloud.database();
const userTable = db.collection('user');
const dbCmd = db.command
​
//注册
function register(openId){
  if(!openId){
    return
  }else{
    return new Promise(async (resolve,reject)=>{
      let nowTime=new Date()
      await userTable.add({userName:"momo",openId:openId,createTime:nowTime.toLocaleString()})
      const res=await checkOpenID(openId)
      resolve(res)
    })
  }
}
//用openId查询数据库
function checkOpenID(openId){
  return new Promise(async (resolve,reject)=>{
    let res = await userTable.where({
      openId:dbCmd.eq(openId)
    }).get()
    resolve(res.data)
  })
}
module.exports = {
  _before: function () { // 通用预处理器
  },
  /**
   * myLogin方法描述
   * @param {string} param 参数1描述
   * @returns {object} 返回值描述
   */
  async myLogin(param) {
    // 参数校验,如无参数则不需要
    
    if (!param) {
      return {
        errCode: 'PARAM_IS_NULL',
        errMsg: 'code不能为空'
      }
    }
    // 业务逻辑
    const URL = `https://api.weixin.qq.com/sns/jscode2session?appid=${config.appid}&secret=${config.secret}&js_code=${param.code}&grant_type=authorization_code`
    const requestOptions = {
      method: 'GET',
      dataType: 'json'
    }
    const res1 = await uniCloud.httpclient.request(URL,requestOptions)
    if(res1.status==200){
      const token=encrypt(JSON.stringify(res1.data))
      const userList=await checkOpenID(res1.data.openid)
      if(userList.length>=1){
        //在user表中更新token,返回新token
        return {
          code:10000,
          msg:'登录成功',
          token:token,
          id:userList[0]._id
        }
      }else{
        //注册用户
        const registerInfo=await register(res1.data.openid)
        //返回token
        return {
          code:10001,
          msg:'注册并登录成功',
          token:token,
          id:registerInfo[0]._id
        }
      }
    }else{
      return {
        code:10001,
        msg:'从微信获取session_id失败'
      }
    }
  }
}

八,前端发起请求携带token

到目前为止,我们已经将自定义的token返回给前端,前端这时候则需要拿到token保存起来,并且在下一次接口请求时携带这个token.

于是在app.vue文件中就可以写:

      if(!token){
        console.log("233333")
        wx.login({
          async success (res) {
            let result=res
            if (result.code) {
              //发起网络请求
              let params={
                code:result.code
              }
              const myLogin = uniCloud.importObject('login') // 导入云对象
              const res2 = await myLogin.myLogin(params)
+             if(res2.code=10000){
+               uni.setStorageSync('token',res2.code)
+             }
            } else {
                console.log('登录失败!' + res.errMsg)
            }
            }
        })
      }

然后我们接着写一个页面,修改完善用户信息的.

第一步:我们首先需要调接口获取到用户信息

于是还是在login云对象中新建一个方法,作为接口.

  //获取用户信息
  async getUserInfo(param){
    const {token}=param
    let result=JSON.parse(decrypt(token))
    const openId=result.openid
    const res =await checkOpenID(openId)
    return {
      code:10000,
      data:res[0],
      msg:'查询用户信息成功'
    }
  },

第二步:在前端页面中进行调用:

<template>
  <view class="userinfo-box">
    <view class="header-box">
      <view class="item-box">
        <view class="left-title">
          昵称:
        </view>
        <view class="right-content">
          <input class="uni-input" focus v-model="name" />
        </view>
      </view>
      
    </view>
    <view class="bottom-btn" @click="save">
      保存
    </view>
  </view>
</template><script>
  export default {
    data() {
      return {
        name:''
      };
    },
    methods:{
      save(){
        console.log("保存修改",this.name)
      }
    },
    async onLoad(){
      const token=uni.getStorageSync('token')
        const myLogin = uniCloud.importObject('login') // 导入云对象
        const res2 = await myLogin.getUserInfo({
        token:token
      })
      if(res2.code=10000){
        this.name=res2.data.userName
      }
    }
  }
</script><style lang="scss" scoped>
.userinfo-box{
  background-color: pink;
  height: 100vh;
  padding: 20rpx 50rpx;
  box-sizing: border-box;
}
.header-box{
  margin: 100rpx 0;
  .item-box{
    display: flex;
    justify-content: space-between;
    
    .left-title{
      width: 120rpx;
    }
    .right-content{
      flex: 1;
      border-bottom: 1rpx solid #eee;
    }
  }
}
.bottom-btn{
  width: 70%;
  margin: 0 auto;
  text-align: center;
  height: 100rpx;
  line-height: 100rpx;
  background: skyblue;
}
</style>

实现的效果:

4.png

值得注意的是,小程序中,在onLaunch 中的请求是异步的,也就是说在执行 onLaunch 后页面 onLoad 就开始执行了,而不会等待 onLaunch 异步返回token后再执行,这就导致了页面无法拿到 onLaunch 中初次登陆的token。这明显是有问题的,我们想要的是在app.vue中的 onLaunch 执行完毕后再执行页面代码.

具体的解决方案可以看这篇文章:uni-app 中实现 onLaunch 异步回调后执行 onLoad 最佳实践 - 掘金 (juejin.cn)

我采用的是第一种方法.这个方法挺有意思的,其实就是利用promise.在vue的原型对象上存储一个promise,并且存储它的resolve方法.

然后就可以将resolve在其他地方使用了,于是页面上的代码只要使用个await就能等待onLaunch中的promise状态改变后再执行.

九,修改用户信息

现在我们已经拿到了用户的信息,并在前端页面上进行了修改,那么接下来,就需要把这个修改提交到数据库.

同样的,第一步需要编写后端接口,方便起见,我依旧是在login云对象中处理这段逻辑:

  //修改用户信息
  async changeUserInfo(param){
    const {token,userName}=param
    let result=JSON.parse(crypt.decrypt(token))
    const openId=result.openid
    //先判断有没有同名的账号
    let res=await userTable.where({userName:dbCmd.eq(userName)}).get()
    if(res.data.length>0&& userName!='momo'){
      return {
        code:10000,
        msg:'该昵称已存在'
      }
    }else{
      const res2=await userTable.where({openId:dbCmd.eq(openId)}).update(
        {
          userName:userName
        }
      )
      return {
        code:10000,
        msg:'修改昵称成功'
      }
    }
  },

接着,在前端页面进行调用:

async save(){
  const myLogin = uniCloud.importObject('login') // 导入云对象
  const res2 = await myLogin.changeUserInfo({
    token:this.token,
    userName:this.name
  })
  if(res2.code==10000){
    uni.showToast({
      title: res2.msg,
      icon:'error',
      duration: 2000
    });
  }}

自此我们已经完成了微信小程序的登录,并在业务逻辑的接口中携带token.

大体的流程就是这样啦.

十,我的小程序体验

主要是一个文案记录的小程序,我自己使用的.可以扫码体验下.

01.jpg

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
好的,让我们开始吧!创建微信小程序需要以下步骤: 1. 注册微信小程序账号 在微信公众平台注册一个小程序账号。如果您没有微信公众号账号,需要先注册一个公众号账号。在注册小程序账号时,需要提供您的身份证信息进行实名认证。 2. 创建新的小程序 进入小程序后台,点击“开发”-“开发设置”-“新增小程序”-“小程序名称”填写您的小程序名字,点击“提交”即可。 3. 配置小程序信息 在小程序后台,点击“开发”-“开发设置”-“基本设置”可以设置小程序的基本信息,如小程序的头像、简介、关联公众号等。 4. 开发小程序小程序后台,点击“开发”-“开发设置”-“开发者工具”下载并安装开发者工具。打开开发者工具后,可以创建小程序项目,编写代码并进行调试。 5. 发布小程序小程序后台,点击“提交审核”进行小程序审核,并在审核通过后进行发布。 下面是一个简单的微信小程序开发示例: 1. 创建项目 打开微信开发者工具,点击“新建小程序项目”按钮,填写项目信息,包括小程序名称、AppID、项目目录、代码类型等。 2. 编写代码 使用开发者工具中提供的代码编辑器,在项目目录中编写小程序代码。这里我们以一个简单的“Hello World”小程序为例,代码如下: ``` //index.js Page({ data: { text: "Hello World" } }) ``` ``` <!-- index.wxml --> <view>{{text}}</view> ``` 3. 预览小程序 在开发者工具中,点击“预览”按钮,可以预览小程序的效果。可以通过手机扫描预览二维码,在手机端进行预览。 4. 发布小程序小程序开发完成后,可以在小程序后台进行提交审核。审核通过后,可以在小程序后台进行发布。 希望这个简单的示例能够帮助您了解微信小程序的开发流程。如果您需要更详细的指导,可以参考微信小程序开发文档或者找专业的小程序开发公司寻求帮助。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值