一,微信程序的登录流程概述
其实uniclould有uni-id来实现登录的一系列逻辑,但是它太多对我而言无用的数据了.我只需要简单的数据.那就自己写呗.
微信官网已经把登录的流程写得很清楚了,官网地址:小程序登录 | 微信开放文档 (.com)
首先小程序通过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接口
依旧是使用云对象的方式,右键云服务器的云对象文件夹,新建云对象:
然后书写如下代码:
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,然后在该文件夹下安装加解密依赖:
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库.
然后修改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数据表:
然后在login云对象中新建注册用户的方法:获取该数据表,查询是否已存在用户,不存在则新增用户.
于是完整的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"); 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>
实现的效果:
值得注意的是,小程序中,在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.
大体的流程就是这样啦.
十,我的小程序体验
主要是一个文案记录的小程序,我自己使用的.可以扫码体验下.
到此这篇手把手云开发小程序-(三)_uniclould小程序的登录的文章就介绍到这了,更多相关内容请继续浏览下面的相关推荐文章,希望大家都能在编程的领域有一番成就!版权声明:
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若内容造成侵权、违法违规、事实不符,请将相关资料发送至xkadmin@xkablog.com进行投诉反馈,一经查实,立即处理!
转载请注明出处,原文链接:https://www.xkablog.com/goyykf/10907.html