当前位置:网站首页 > Go语言开发 > 正文

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

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

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

微信官网已经把登录的流程写得很清楚了,官网地址:小程序登录 | 微信开放文档 (.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..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("") 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.

参考的官网地址:小程序登录 | 微信开放文档 (.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..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("23456"); // 十六位十六进制数作为密钥偏移量 const SECRET_IV = CryptoJS.enc.Utf8.parse("23456"); 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..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..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("") 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

到此这篇手把手云开发小程序-(三)_uniclould小程序的登录的文章就介绍到这了,更多相关内容请继续浏览下面的相关推荐文章,希望大家都能在编程的领域有一番成就!

版权声明


相关文章:

  • 手把手云开发小程序-(四)-uniclould增删改查业务开发2024-11-29 14:36:09
  • 手把手云开发小程序-(五)-小程序的发布和上线2024-11-29 14:36:09
  • tomcat和Servlet开发小案例2024-11-29 14:36:09
  • Web应用开发框架-egg进阶与实战(二)01——mongoose简介2024-11-29 14:36:09
  • 网络爬虫开发(五)01-爬虫高级——Selenium简介 & 根据平台选择安装selenium-webdriver包 & Selenium的基本使用2024-11-29 14:36:09
  • 手把手云开发一个小程序-(二)-uniclould的购买和默认库的使用2024-11-29 14:36:09
  • 手把手云开发一个小程序-(一)-搭建项目框架2024-11-29 14:36:09
  • 《第一行代码》 第三章:UI布局开发2024-11-29 14:36:09
  • unicloud开发微信小程序-云公共模块的使用2024-11-29 14:36:09
  • 库开发者如何配置babel,@babel/plugin-transform-runtime的配置说明2024-11-29 14:36:09
  • 全屏图片