微信小程序登入前后端 后端springboot

初衷

公司要入小程序的坑,好久没写微信小程序,重新梳理一下登入逻辑。正好自己最近在看springBoot,所以也算一个前后端的小Demo,也算个人阶段性质的检验吧。

只是个人方案,不是标准。如果有问题,欢迎指正。

技术站
前端

微信原生

后端

springboot + mysql + MP + jwt

设计

在这里插入图片描述
前端缓存数据,都是假象。所以isAuth来判断是否用户授权。(即有用户信息)

需求分析
  • 验证是否有token(此token只是jwt生成的,不是小程序平台的access_token)
    • 存在
      此时调用接口获取用户信息,看是否已授权用户信息 isAuth
      • 未授权
        跳到授权页面。按钮授权,获取用户信息,存储用户信息和isAuth=true。再返回首页
      • 已授权
        放行,回到默认首页
    • 不存在
      • wx.login获取code,接入后台接口获取(openId),返回token 储存openId(此时无用户信息)。跳到授权页面,获取用户信息和isAuth
前端代码

app.js

// app.js
App({
  onLaunch() {
	// 小程序生命周期,只有小程序加载完成时才运行一次,且从后台唤醒不触发。但凡接口获取的信息在这里不会及时反馈。所以我在onShow中
  },
  onShow() {
    if (!wx.getStorageSync('token') ) {
      // 登录
      wx.login({
        success: res => {
          if (res.code) {
            wx.request({
              url: 'http://localhost:9527/wx/posden-spring-wx-user/getOpenId',
              data: {
                code: res.code
              },
              success: (res) => {
                var openid = res.data.data.openid
                this.globalData.openId = openid
                // 将用户信息添加到数据库 (未授权时 数据库只有openId)接口isAuth是否用户已授权
                wx.request({
                  url: 'http://localhost:9527/wx/posden-spring-wx-user/saveOrUpdateUser',
                  method: 'POST',
                  data: {
                    openId: openid
                  },
                  success: (res) => {
                    // token 本地存储
                    wx.setStorageSync('token', res.data.data.token)
                    if(!res.data.data.userInfo.isAuth){
                      wx.reLaunch({
                        url: '/pages/index/index',
                      })
                    }
                  }
                })
              },
              fail: (error) => {
                console.log(error)
              }
            })
          }
        }
      })
    }else {
      this.queryUsreInfo()
    }
  },
    //获取用户信息接口
  queryUsreInfo: function () {

	// 这里获取的用户信息是及时的(比如你换了头像,但数据库没更新),但还是存在一开始的问题,自己定义的后台接口权限问题,比如我后台不想获取用户信息,虽然你本地小程序权限已放开,但还是不行。你可以在你小程序加个刷新用户信息的功能。
	
    // wx.getSetting({
    //   success: function (res) {
    //     if (res.authSetting['scope.userInfo']) {
    //       wx.getUserInfo({
    //         success: function (res) {
    //           //从数据库获取用户信息
    //           console.log(res)
    //         }
    //       });
    //     }
    //   }
    // })



      wx.request({
        url: 'http://localhost:9527/wx/posden-spring-wx-user/getUserInfo',
        header: {
          'content-type': 'application/json',
          'token': wx.getStorageSync('token')
        },
        success: (res)=> {
          var userInfo = res.data.data.userInfo
          console.log(userInfo.isAuth)
          if(userInfo.isAuth){
            wx.reLaunch({
              url: '/pages/home/home',
            })
          }else{
            wx.reLaunch({
              url: '/pages/index/index',
            })
          }
        }
      })
    },
  globalData: {
    userInfo: null,
    openId: '',
  }
})
授权页面

index.wxml

<!--index.wxml-->
<view wx:if="{{canIUse}}">
    <view class='header'>
        <image src='xxxxx.jpg'></image>
    </view>

    <view class='content'>
        <view>申请获取以下权限</view>
        <text>获得你的公开信息(昵称,头像等)</text>
    </view>

    <button class='bottom' type='primary' open-type="getUserInfo" lang="zh_CN" bindgetuserinfo="bindGetUserInfo">
        授权登录
    </button>
</view>

<view wx:else>请升级微信版本</view>

index.wcss

/**index.wxss**/
.header {
  margin: 90rpx 0 90rpx 50rpx;
  text-align: center;
  width: 650rpx;
  height: 300rpx;
  line-height: 450rpx;
}

.header image {
  width: 200rpx;
  height: 200rpx;
  border-radius: 50%
}

.content {
  margin-left: 50rpx;
  margin-bottom: 90rpx;
}

.content text {
  display: block;
  color: #9d9d9d;
  margin-top: 40rpx;
}

.bottom {
  border-radius: 80rpx;
  margin: 70rpx 50rpx;
  font-size: 35rpx;
}

index.js

const app = getApp();
Page({
  data: {
    //判断小程序的API,回调,参数,组件等是否在当前版本可用。
    canIUse: wx.canIUse('button.open-type.getUserInfo'),
  },
  onLoad: function () {
    var that = this;
    // 查看是否授权
    wx.getSetting({
      success: function (res) {
        if (res.authSetting['scope.userInfo']) {
          wx.getUserInfo({
            success: function (res) {
              //从数据库获取用户信息
              that.queryUsreInfo();
              //用户已经授权过
              wx.redirectTo({
                url: '/pages/home/home'
              })
            }
          });
        }
      }
    })
  },
  bindGetUserInfo: function (e) {
    if (e.detail.userInfo) {
      //用户按了允许授权按钮
      var that = this;
      //插入登录的用户的相关信息到数据库

      const {
        userInfo,
        encryptedData,
        iv,
        signature
      } = e.detail
      this.saveOrAdd(userInfo)

    } else {
      //用户按了拒绝按钮
      wx.showModal({
        title: '警告',
        content: '您点击了拒绝授权,将无法进入小程序,请授权之后再进入!!!',
        showCancel: false,
        confirmText: '返回授权',
        success: function (res) {
          if (res.confirm) {
            console.log('用户点击了“返回授权”')
          }
        }
      })
    }
  },
  // 更新数据库信息
  saveOrAdd: function (userInfo) {
    wx.request({
      url: 'http://localhost:9527/wx/posden-spring-wx-user/saveOrUpdateUser',
      method: 'POST',
      data: {
        openId: getApp().globalData.openId,
        nickName: userInfo.nickName,
        avatarUrl: userInfo.avatarUrl,
        province: userInfo.province,
        city: userInfo.city,
        gender: userInfo.gender,
        country: userInfo.country,
        isAuth: true  // 授权标识
      },
      header: {
        'content-type': 'application/json'
      },
      success: (res)=> {
        wx.setStorageSync('token', res.data.data.token)
        //从数据库获取用户信息
        wx.reLaunch({
          url: '/pages/home/home'
        })
      }
    });
  },

      //获取用户信息接口
      queryUsreInfo: function () {
        wx.request({
          url: 'http://localhost:9527/wx/posden-spring-wx-user/getUserInfo',
          header: {
            'token': wx.getStorageSync('token')
          },
          success: (res)=> {
            var userInfo = res.data.data.userInfo
            getApp().globalData.userInfo = userInfo
          }
        })
      },
})
前端展示效果

在这里插入图片描述
在这里插入图片描述

后端代码

有好的写法,或者有bug,欢迎交流。

package com.example.demo.wx.controller;


import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.demo.annotation.NeedLogin; // api需要token的的注解
import com.example.demo.utils.AppletsWeChatUtil;// 封装加密解密unionId的方法
import com.example.demo.utils.HttpUtil; // 封装http的工具类
import com.example.demo.utils.JwtUtil; // 封装jwt的工具类
import com.example.demo.utils.ReturnParam; // 封装的返回类
import com.example.demo.wx.entity.PosdenSpringWxUser;
import com.example.demo.wx.entity.UnicodeParamsDTO;
import com.example.demo.wx.server.PosdenSpringWxUserService; 
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;

/**
 * <p>
 *  前端控制器
 * </p>
 *
 * @author posden
 * @since 2021-01-20
 */
@RestController
@RequestMapping("/wx/posden-spring-wx-user")
public class PosdenSpringWxUserController {

    @Resource
    PosdenSpringWxUserService posdenSpringWxUserService;

    private static final String appId = "wxa59f8c8d5c53c7ce";
    private static final String appSecret = "60edd3c6a302d3a10bf89490b73bac28";

    // 只获取openId
    @GetMapping("/getOpenId")
    public ReturnParam<Object>  getUnicodeIdPassAuth(@RequestParam String code) {
        String result = HttpUtil.get("https://api.weixin.qq.com/sns/jscode2session?appid="+appId+"&secret="+appSecret+"&js_code="+code+"&grant_type=authorization_code");
        JSONObject res = JSONObject.parseObject(result);
        ReturnParam<Object> returnParam = new ReturnParam<>();
        returnParam.setSuccess(true);
        returnParam.setData(res);
        return returnParam;
    }

    // 通过解密方法获取openId和unionId  测试小程序好像没有unionId,但其他用户信息数据是有的
    @PostMapping("/getUnicodeIdPassAuth")
    public Map<String, String> getUnicodeIdPassAuth(@RequestBody UnicodeParamsDTO unicodeParamsDTO){
        String encryptedData = unicodeParamsDTO.getEncryptedData();
        String code = unicodeParamsDTO.getCode();
        String iv = unicodeParamsDTO.getIv();
        return AppletsWeChatUtil.oauth2GetUnionId(code,encryptedData,iv);
    }

    // 添加或更新
    @PostMapping("/saveOrUpdateUser")
    public ReturnParam<Object> saveOrUpdateUser(@RequestBody PosdenSpringWxUser posdenSpringWxUser){
        String openId = posdenSpringWxUser.getOpenId();
        QueryWrapper<PosdenSpringWxUser> updateWrapper = new QueryWrapper<>();
        updateWrapper.eq("open_id", openId);

        Boolean isAuth = posdenSpringWxUser.getIsAuth();

        Map<String,String> payload = new HashMap<>();
        payload.put("openId", openId);
        String token = JwtUtil.getToken(payload);
        ReturnParam<Object> returnParam = new ReturnParam<>();

        int count = posdenSpringWxUserService.count(updateWrapper);
        PosdenSpringWxUser item = posdenSpringWxUserService.getOne(updateWrapper);
        if(count == 1) {
            boolean save = posdenSpringWxUserService.update(posdenSpringWxUser, updateWrapper);
            return getObjectReturnParam(isAuth, token, returnParam, item, save);
        }else if(count == 0) {
            boolean save = posdenSpringWxUserService.save(posdenSpringWxUser);
            return getObjectReturnParam(isAuth, token, returnParam, item, save);
        }else {
            returnParam.setSuccess(false);
            return returnParam;
        }
    }

    private ReturnParam<Object> getObjectReturnParam(Boolean isAuth, String token, ReturnParam<Object> returnParam, PosdenSpringWxUser item, boolean save) {
        Map<String, Object> data = new HashMap<>();
        data.put("token", token);
        data.put("isAuth", isAuth);
        data.put("userInfo", item);
        returnParam.setData(data);
        returnParam.setSuccess(save);
        return returnParam;
    }

    @NeedLogin()
    @GetMapping("/getUserInfo")
    public ReturnParam<Object> getUserInfo(HttpServletRequest headers) throws Exception {

        String token = headers.getHeader("token");
        String openId = JwtUtil.getOpenIdFromToken(token);

        QueryWrapper<PosdenSpringWxUser> queryWrapper = new QueryWrapper<>();
        System.out.println(openId);
        queryWrapper.eq("open_id", openId);

        PosdenSpringWxUser one = posdenSpringWxUserService.getOne(queryWrapper);
        System.out.println(one);

        ReturnParam<Object> returnParam = new ReturnParam<>();
        returnParam.setSuccess(true);
        Map<String, Object> data = new HashMap<>();
        data.put("userInfo", one);
        returnParam.setData(data);
        return returnParam;
    }

}

收工

  • 2
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值