👍 点赞,你的认可是我创作的动力!

⭐️ 收藏,你的青睐是我努力的方向!

✏️ 评论,你的意见是我进步的财富!


0总体思路

温馨提示:我做的思路可能是复杂化了,如果你觉得可以更加简便的话欢迎分享到评论区或者自己改写一下我的代码,我的后端是写的很简单的没有什么路由分发是直接写的,你可以自由优化。1-5都是在说前端,如果你想看后端直接跳到第6章就好
小程序的其他部分你可以看看我往期的文章

0.1前端实现:

首先小程序进入首页自动去获取一遍本地存储的用户信息赋值到vuex里面去,用户进入个人中心的时候页面去获取vuex里面的用户信息(头像,昵称),如果发现没有的话就显示登录注册按钮,点击之后跳转到用户授权登录页,用户授权头像和昵称之后点击授权登陆按钮,获取到用户的code传入到后端,后端返回用户信息和token给前端,前端保存到本地存储和vuex里面去

0.2如何阻拦一些页面必须要登陆才能进去呢?

我的逻辑思路是在封装的请求接口里面的请求放获取本地存储的token,如果有就传入后端如果没有就传无给后端,后端在那些需要阻拦登陆的接口前面放中间件,放token验证的中间件,验证这个token解析出来的用户信息是不是这个用户的(这一步我是没有做的,所以我就是介绍一个思路你们可以自己去做)

0.3后端实现

后端解构赋值接受code+头像+昵称,然后拿code去拼接一个链接(看代码)去请求微信官方服务器,我这里的请求是用到了aixos所以记得导入这个第三方库哦!!!,拿拼接好的链接去换取这个用户的openid(这个很重要是用户的唯一标识),换取到openid之后去数据库里面查询用户表里面有没有一条数据包含这个openid的如果没有就是注册,如果有就是登陆(需要注意的是本文代码是没有去注意查看对比用户这次上传的头像和昵称与数据库里面的数据去对比就只是对比了openid来判断用户是注册还是登陆)

1.首页

onLoad是页面加载时,放在js那里和data是同级关系

  onLoad() {
    const user = uni.getStorageSync('user');
    const token = uni.getStorageSync('token');
    this.$store.commit('user', user);
    this.$store.commit('token', token);
  },

2.个人中心页

<view class="head">
  <view class="gr">
    <view v-if="user.avatarUrl && user.nickName" class="user-info">
      <image :src="user.avatarUrl" mode="aspectFill" class="avatar"></image>
      <text class="nickname">{{ user.nickName }}</text>
    </view>
    <view v-else @click="wxlogin()">点击注册登录</view>
  </view>
</view>
      data() {
    return {
      user: {} // 用户信息
    };
  },
  onShow() {
    // 在页面显示时获取vuex中的user信息
    this.user = this.$store.state.user || {};
  },
  methods: {
    wxlogin() {
      uni.navigateTo({
        url: '/pages/login/login'
      });
    },

3.授权登陆页

3.1.获取微信头像和微信昵称

3.1.1官方教程

根据官方给的教程:https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/userProfile.html
官方代码示例:




const defaultAvatarUrl = ‘https://mmbiz.qpic.cn/mmbiz/icTdbqWNOwNRna42FI242Lcia07jQodd2FJGIYQfG0LAJGFxM4FbnQP6yfMxBgJ0F3YRqJCJ1aPAK2dQagdusBZg/0’

Page({
data: {
avatarUrl: defaultAvatarUrl,
},
onChooseAvatar(e) {
const { avatarUrl } = e.detail
this.setData({
avatarUrl,
})
}
})

3.1.2实际实现

我的实际代码示例:获取到头像和昵称然后保存到本页面的数据中

<button open-type=“chooseAvatar” @chooseavatar=“onChooseAvatar”>


<input class=“nickNameInput” type=“nickname” :value=“nickName” placeholder=“请输入您的昵称” @change=“getNickname” />
<button @click=“wxlogin()”>注册登录

getNickname(e) {
this.nickName = e.detail.value;
},
onChooseAvatar(e) {
this.avatar = e.detail.avatarUrl;
console.log(e.detail.avatarUrl);
},

3.2.获取头像和昵称之后去获取code小程序授权登陆

注意就是获取code必须要点击事件,需要用户去点击,可以看官方的:https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/login.html
逻辑思路是先让用户上传完头像和昵称之后让用户去点击授权登陆的按钮,点击之后获取到code然后将这三个数据都传入后端,需要注意的是如果用户没有上传头像和昵称(即这2个数据为空时要阻止授权登陆并提示(我这里没写))
样式css需要自己去调节哦

3.3登陆页的整体代码:

<template>
  <view>
    <button open-type="chooseAvatar" @chooseavatar="onChooseAvatar">
      <img :src="avatar" alt="" srcset="" />
    </button>
    <input class="nickNameInput" type="nickname" :value="nickName" placeholder="请输入您的昵称" @change="getNickname" />
    <button @click="wxlogin()">注册登录</button>
  </view>
</template>
<script>
export default {
  data() {
    return {
      avatar: '',
      nickName: '',
      code: ''
    };
  },
  methods: {
    getNickname(e) {
      this.nickName = e.detail.value;
    },
    onChooseAvatar(e) {
      this.avatar = e.detail.avatarUrl;
      console.log(e.detail.avatarUrl);
    },
    wxlogin() {
      uni.login({
        provider: 'weixin',
        success: (loginRes) => {
          if (loginRes.code) {
            this.code = loginRes.code;
            // 发送 res.code 到后台换取 openId, sessionKey, unionId
            console.log(loginRes.code);
            this.getCode();
          } else {
            console.log('登录失败!' + loginRes.errMsg);
          }
        }
      });
    },
    async getCode() {
      const res = await this.$myRequest({
        method: 'post',
        url: '/wxlogin',
        data: {
          avatar: this.avatar,
          nickName: this.nickName,
          code: this.code
        }
      });
      const user = res.data.user;
      const token = res.data.token;
      // 保存数据到小程序本地存储
      uni.setStorageSync('user', user);
      uni.setStorageSync('token', token);
      // 保存数据到vuex里面去
      this.$store.commit('user', user);
      this.$store.commit('token', token);
      // 返回上一页
      uni.navigateBack();
      console.log(res.data.user);
    }
  }
};
</script>

4.接口封装页

在这个登陆页面我的请求接口是进行封装的然后全局挂载了
新建一个request.js文件,代码如下:

// 设置基础 URL
const BASE_URL = 'http://192.168.0.105:8080';
// 封装请求方法,返回一个 Promise 对象
export const myRequest = (options) => {
  return new Promise((resolve, reject) => {
    // 使用 uni.request 进行请求
    uni.request({
      // 拼接完整的请求 URL
      url: BASE_URL + options.url,
      // 请求方法,默认为 GET
      method: options.method || 'GET',
      // 请求数据,默认为空对象
      data: options.data || {},
      // 请求头部,包含 Authorization 字段,用于携带 Token
      header: {
        Authorization: uni.getStorageSync('token') // 从本地存储中获取 Token
      },
      // 请求成功的回调函数
      success: (res) => {
        resolve(res); // 将成功的响应传递给 Promise 的 resolve 函数
      },
      // 请求失败的回调函数
      fail: (err) => {
        // 在页面上显示请求失败的提示信息
        uni.showToast({
          title: '请求接口失败'
        });
        reject(err); // 将失败的错误对象传递给 Promise 的 reject 函数
      }
    });
  });
};

新建完文件之后还需要在mian.js导入进行全局挂载进行使用:

import {
  myRequest
} from './common/request.js'

Vue.prototype.$myRequest = myRequest

5.全局变量vuex页

5.1代码:

我这里是用vuex去管理全局变量的,就是将用户信息和token保存到vuex里面去,你们也可以保存你们想要的全局变量到vuex里面去方便使用
新建一个store目录里面新建一个index.js文件,里面代码如下:

import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
  state: {
    //公共的变量,这里的变量不能随便修改,只能通过触发mutations的方法才能改变
    user: null, //用户信息
    token: null, //登陆令牌
    communityId: 1 //小区id
  },
  mutations: {
    //相当于同步的操作
    user(state, user) {
      state.user = user;
    },
    token(state, token) {
      state.token = token;
    },
    communityId(state, communityId) {
      state.communityId = communityId;
    }
  },
  actions: {
    //相当于异步的操作,不能直接改变state的值,只能通过触发mutations的方法才能改变
  }
})
export default store

搞完之后到mian.js文件去导入然后全局挂载:

import store from './store/index.js'
Vue.prototype.$store = store

5.2使用方法:

5.2.1.保存数据到vuex

保存数据到vuex里面去的话就是需要你先在这个inde.js新建一个变量并且你还需要新建一个方法就是用来操作的比如说:

//相当于同步的操作
user(state, user) {
  state.user = user;
},

你可以按照这个的格式新建其他数据的操作方法,然后我这里保存user数据的话就是代码如下:

  // 保存数据到vuex里面去
  this.$store.commit('user', user);

5.2.2.获取数据的就是代码如下:

//获取vuex里面的用户信息
this.user = this.$store.state.user

6.后端实现

6.1封装一个数据库的连接请求

新建一个sql.js然后再导入到app.js
var mysql = require(‘mysql’); //引入
var connection = mysql.createConnection({
host: ‘localhost’,
user: ‘root’,
password: ‘root’,
database: ‘zxjy’
});
module.exports = connection; //抛出

6.2登陆授权的接口实现

提示:cors是为了用来跨域的,axios是用来做微信请求的,jsw是用来生成token的,还有上面那个sql都是第三方包需要记得用npm install哦!!!以及那个内容需要自己设置一下哦比如说appid,密钥啥的

const express = require('express')
const connection = require('./sql.js');
const cors = require('cors'); //配置 CORS 策略
const axios = require('axios'); //网络请求模块,用来请求那个微信服务器的openid
const jwt = require('jsonwebtoken'); //生成 Token 
// 1.创建express的服务器
const app = express()
const appid = ""; //自己小程序后台管理的appid,可登录小程序后台查看
const mysecret = ""; //小程序后台管理的secret,可登录小程序后台查看
const grant_type = "authorization_code"; // 授权(必填)默认值
const secretKey = ''; //jwt的密钥
// 封装微信API请求
async function wxlogin(code) {
  const url =
    `https://api.weixin.qq.com/sns/jscode2session?appid=${appid}&secret=${mysecret}&js_code=${code}&grant_type=${grant_type}`;
  try {
    const response = await axios.get(url);
    return response.data;
  } catch (error) {
    console.error(error);
    throw error;
  }
}

app.use(cors()); // 使用 CORS 中间件  
app.use(express.json()); // 解析 POST 请求的请求体
//注册登录的接口
app.post('/wxlogin', async (req, res) => {
  let code = req.body.code; //登陆传过来的code
  let nickName = req.body.nickName;
  let avatarUrl = req.body.avatar;
  const params = await wxlogin(code);
  let openid = params.openid //查询一下这个openid是否存在数据库来判断用户是登陆还是注册,没有判断头像或者昵称是否更新
  connection.query('SELECT * FROM user WHERE openId = ?', [openid], (error, results) => {
    if (error) {
      console.error(error);
      return res.status(500).json({
        error: 'Internal Server Error'
      });
    }
    if (results.length > 0) {
      // 用户已存在
      const user = {
        id: results[0].id,
        nickName: results[0].name,
        avatarUrl: results[0].avatar
      };
      // 生成 Token
      const token = jwt.sign(user, secretKey, {
        expiresIn: '9999h'
      }); // Token 有效期为9999小时
      return res.json({
        message: '用户已存在',
        token,
        user
      });
    } else {
      // 用户不存在,需要注册
      // 使用昵称、头像、openid 插入新用户到数据库
      connection.query('INSERT INTO user (openId, name, avatar) VALUES (?, ?, ?)', [openid,
        nickName, avatarUrl
      ], (error, insertResult) => {
        if (error) {
          console.error(error);
          return res.status(500).json({
            error: 'Internal Server Error'
          });
        }
        const userId = insertResult.insertId; // 获取插入的用户的 id
        const user = {
          id: userId,
          nickName,
          avatarUrl
        };
        return res.json({
          message: '用户注册成功',
          token,
          user
        });
      });
    }
  });
})
Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐