微信小程序前后端授权登陆

2,825 阅读4分钟

我正在参加「掘金·启航计划」

一、微信小程序前端

1.1 小程序前端准备

微信公众平台注册一个小程序,注册完成之后你就有APPIDSECRET

1、api封装

根目录下定义wxapi文件夹,我们将api请求独立出来封装,在wxapi文件夹下写入request.js

const requestObj = require('./request.config.js')

requestObj.request = ({
  url,
  method,
  data = '',
  token = ''
}) => {
  let _url = requestObj.API_BASE_URL + url
  return new Promise((resolve, reject) => {
    wx.showLoading({
      title: '加载中...',
    })
    wx.request({
      url: _url,
      method: method,
      data,
      header: {
        // 'content-type': 'application/x-www-form-urlencoded',
        'Content-Type': 'application/json',
        'Authorization': 'Bearer ' + token
      },
      success(request) {
        console.log(request)
        if (request.data.code == 401) {
          wx.navigateTo({
            url: '/pages/authpage/authpage',
          })
          wx.showToast({
            title: '请重新登录',
            icon: 'none'
          })
        }
        resolve(request.data)
      },
      fail(error) {
        reject(error)
        wx.navigateTo({
          url: '../networkerror/networkerror',
        })
      },
      complete() {
        // 加载完成
        wx.hideLoading()
      }
    })
  })
}
/**
 * 小程序的promise扩展finally方法
 */
Promise.prototype.finally = function (callback) {
  var Promise = this.constructor;
  return this.then(
    function (value) {
      Promise.resolve(callback()).then(
        function () {
          return value;
        }
      );
    },
    function (reason) {
      Promise.resolve(callback()).then(
        function () {
          throw reason;
        }
      );
    }
  );
}

module.exports = requestObj

我们将相关的配置写入request.config.js(与request.js同层目录):

const requestObj = {
  API_BASE_URL: 'http://jtminiprogramapi.com/api', // 小程序接口线上地址
  // API_BASE_URL: 'http://192.168.91.112:8085/',  // 小程序接口线下地址
}

module.exports = requestObj

再在wxapi文件夹创建api文件夹,里面写我们各个模块的apisapis文件夹下写入userApi.js(我们将用户相关的接口全部写在这这里只演示用户登陆):

const requestObj = require('../request')

let userApi = {
  /* 微信登录获取token */
  getToken: (data, method) => requestObj.request({
    url: '/wxlogin', method: method, data
  }),

}

module.exports = userApi;

wxapi文件夹下写入index.js

const userApi = require('./apis/userApi');
module.exports = {
  userApi,
}

api分模块封装完毕,它的目录结构如下: 在这里插入图片描述


2、授权独立页面

微信开发者工具中写入独立授权页面: authpage.wxml

<view class='headView'>
  <open-data class='icon' mode="aspectFit" type="userAvatarUrl"></open-data>
  <view class='icon'></view>
</view>
<view class="auth-btn">
   <button bindtap="getUserProfile">授权登录</button>
</view>
<view class="cancel-btn" bindtap="cancelAuth">取消授权登录</view>
<van-toast id="van-toast" />


authpage.js

import Toast from '@vant/weapp/toast/index';
const WXAPI = require('../../wxapi/index');
Page({

  /**
   * 页面的初始数据
   */
  data: {

  },
  // 点击取消授权
  cancelAuth () {
    wx.switchTab({
      url: '../index/index'
    })
  },
  getUserProfile () {
    wx.getUserProfile({
      desc: '完善个人资料', // 声明获取用户个人信息后的用途,后续会展示在弹窗中,请谨慎填写
      success: (newWes) => {
        let userInfo = newWes.userInfo
        wx.setStorageSync('userInfo', newWes.userInfo)

        wx.login({
          success (res) {
            let code = res.code
            if (code) {
              wx.showLoading({
                title: '加载中',
              })
              WXAPI.userApi.getToken({
                userInfo,
                code
              }, 'POST').then((res) => {
                console.log(res)
                wx.setStorageSync('authFlag', true)
                wx.setStorageSync('token', res.access_token)
                wx.navigateBack({
                  delta: 1
                })
              }, (err) => {
                console.log(err)
              }).finally(() => {
                wx.hideLoading({})
              })
            }
          }
        })
      },
      fail: (err) => {
        console.log(err)
      }
    })
  },
  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {

  },

  /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady: function () {

  },

  /**
   * 生命周期函数--监听页面显示
   */
  onShow: function () {

  },

  /**
   * 生命周期函数--监听页面隐藏
   */
  onHide: function () {

  },

  /**
   * 生命周期函数--监听页面卸载
   */
  onUnload: function () {

  },

  /**
   * 页面相关事件处理函数--监听用户下拉动作
   */
  onPullDownRefresh: function () {

  },

  /**
   * 页面上拉触底事件的处理函数
   */
  onReachBottom: function () {

  },

  /**
   * 用户点击右上角分享
   */
  onShareAppMessage: function () {

  }
})

authpage.wxss

.headView {
  display: flex;
  justify-content: center;
  align-items:center;
  margin-top: 50rpx;
  height:300rpx;
  width:750rpx;
  position:relative;
  margin-bottom: 50rpx;
  }
 
/**
*open-data 的头像做不了圆角
*这里是覆盖一个镂空的view在上面 镂空view的边界做成与周围背景颜色一样 做了伪圆角
**/
.headView .icon {
    position: absolute;
    height: 200rpx;
    width: 200rpx;
    border-radius: 50%;
    border: 50rpx solid #f1f1f1;
}
.cancel-btn {
    display: block;
    margin-left: auto;
    margin-right: auto;
    padding-left: 14px;
    padding-right: 14px;
    box-sizing: border-box;
    font-size: 18px;
    text-align: center;
    text-decoration: none;
    line-height: 2.55555556;
    border-radius: 5px;
    -webkit-tap-highlight-color: transparent;
    overflow: hidden;
    cursor: pointer;
    color: #000;
    background-color: #f8f8f8;
    margin-top: 50rpx;
    padding: 8px 24px;
    line-height: 1.41176471;
    border-radius: 4px;
    font-weight: 700;
    font-size: 17px;
    width: 184px;
    margin-left: auto;
    margin-right: auto;
    position: relative;
}
.auth-btn {
  width: 184px;
  margin: 0 auto;
  height: 40px;
}
button {
  height: 100%;
  line-height: 40px;
  font-weight: normal;
  background-color: #546D7A;
  color: #fff;
}
button::after {
  border: none;
}
.cancel-btn {
  font-weight: normal;
}

authpage.json

{
  "usingComponents": {
    "van-toast": "@vant/weapp/toast/index"
  },
  "navigationBarTitleText": "授权登录"
}

二、微信小程序后端(laravel)

2.1 小程序后端准备

1、项目安装dingo/api以及jwt认证

可以参考我的这篇文章。

2、创建小程序用户表和模型

运行命令php artisan make:Model miniProgram/mpUser -m在这里插入图片描述 迁移文件写入字段:

Schema::create('mp_users', function (Blueprint $table) {
            $table->id();
            $table->string('openid')->comment('用户小程序唯一id');
            $table->string('nickname')->comment('用户小程序昵称');
            $table->string('avatar')->comment('用户小程序头像');
            $table->string('country')->comment('用户小程序国家');
            $table->string('province')->comment('用户小程序省份');
            $table->string('city')->comment('用户小程序城市');
            $table->string('weixin_session_key')->comment('用户登陆session');
            $table->string('gender')->comment('用户性别: 1 -> 男,0 -> 女');
            $table->string('name')->nullable()->comment('用户真实姓名');
            $table->string('email')->nullable()->comment('用户邮箱');
            $table->timestamps();
        });

在这里插入图片描述 运行迁移命令php artisan migrate在这里插入图片描述


3、安装easywechat插件

这个插件让你更快的对接微信的接口。 运行命令composer require "overtrue/laravel-wechat:^6.0"在这里插入图片描述


在中间件 App\Http\Middleware\VerifyCsrfToken 排除微信相关的路由: 在这里插入图片描述


运行命令php artisan vendor:publish --provider="Overtrue\LaravelWeChat\ServiceProvider"发布相关配置。 在config/wechat.php中将小程序的配置打开: 在这里插入图片描述 然后在.env文件下写入: 在这里插入图片描述


4、创建小程序授权登陆认证控制器

运行命令php artisan make:controller Auth/mpAuthorizationsController在这里插入图片描述 写入方法:

<?php

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use App\Models\miniProgram\mpUser;
use GrahamCampbell\ResultType\Result;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;

class mpAuthorizationsController extends Controller
{
    /**
     * name:SWT用户登录,小程序微信登录
     */
    public function store(Request $request)
    {
        Log::debug($request->all());
        $code = $request->code;
        $nick_name = $request->userInfo['nickName'];
        $avatar = $request->userInfo['avatarUrl'];
        $gender = $request->userInfo['gender'];
        $country = $request->userInfo['country'];
        $province = $request->userInfo['province'];
        $city = $request->userInfo['city'];

        // 根据 code 获取微信 openid 和 session_key
            $miniProgram = \EasyWeChat::miniProgram();
            $data = $miniProgram->auth->session($code);

        // 如果结果错误,说明 code 已过期或不正确,返回 401 错误
        if (isset($data['errcode'])) {
            return Result::fail('code不正确');
        }

        // 找到 openid 对应的用户
        $userInfo = mpUser::where('openid', $data['openid'])->first();

        $attributes['weixin_session_key'] = $data['session_key'];
        if(!$userInfo){
            //更新用户信息
            $userInfo = new mpUser();
            $userInfo->openid = $data['openid'];
            $userInfo->weixin_session_key = $data['session_key'];
            $userInfo->nickname = $nick_name;
            $userInfo->avatar = $avatar;
            $userInfo->gender = $gender;
            $userInfo->country = $country;
            $userInfo->province = $province;
            $userInfo->city = $city;

            $userInfo->save();
        }else{
            // 更新用户数据
            $userInfo->update($attributes);
        }


        // 为对应用户创建 JWT
        $token = auth('api')->login($userInfo);
        return $this->respondWithToken($token)->setStatusCode(201);

    }

     /**
     * Get the token array structure.
     *
     * @param  string $token
     *
     * @return \Illuminate\Http\JsonResponse
     */
    protected function respondWithToken($token)
    {
        return response()->json([
            'status_code' => '1',
            'msg' => '登陆成功!',
            'access_token' => $token,
            'token_type' => 'Bearer',
            'expires_in' => auth('api')->factory()->getTTL() * 60
        ]);
    }

}


5、授权登陆路由

routes/api.php

<?php

use App\Http\Controllers\Auth\mpAuthorizationsController;

$api = app('Dingo\Api\Routing\Router');

$api->version('v1', function ($api) {

    // 需要登陆的路由
    $api->group(['middleware' => 'api.auth'], function($api) {
        $api->get('users', [\App\Http\Controllers\TestController::class, 'users']);
    });

    // 执行登陆
    $api->any('wxlogin', [mpAuthorizationsController::class, 'store']);
});


三、测试效果

在这里插入图片描述 在这里插入图片描述 小程序端已发送请求并且拿到了token。 接着我们去看下数据库中是否有我们登陆小程序的用户信息,以及需要和微信服务器打交道的session_key在这里插入图片描述 可以看到这边我们相关的用户信息基本都有了,头像昵称openidsession_key

在学习实战的路上,如果你觉得本文对你有所帮助的话,那就请关注点赞评论三连吧,谢谢,你的肯定是我写博的另一个支持。