• 微信小程序结合php后台实现登录授权机制详解


    微信小程序应用的用户登录授权机制相当复杂,官方给出了下面一张流程图来解释:

    下面结合这张图来详细讲述下小程序的登录验证授权机制。

    首先,小程序应用实现登录验证的前提是需要在微信开放平台注册一个开发者账号,申请到AppID 和 AppSecret。并申请开启“获取用户信息”的权限。

    然后 ,在小程序中使用微信提供的 wx.login 接口获取用户的临时登录凭证 code。代码示例如下:

     

    复制代码
    // 检查用户是否已经授权
    wx.getSetting({
      success: res => {
        if (res.authSetting['scope.userInfo']) {
          // 用户已经授权,可以直接调用 wx.getUserProfile 获取用户信息
          wx.getUserProfile({
            desc: '获取用户信息',
            success: res => {
              // 获取用户信息
              const userInfo = res.userInfo;
              // 获取用户登录凭证
              wx.login({
                success: res => {
                  // 获取用户登录凭证
                  const code = res.code;
    
                  // 将 code 和 userInfo 发送到后台服务器进行处理
                  wx.request({
                    url: 'https://example.com/login.php',
                    data: {
                      code: code,
                      userInfo: userInfo
                    },
                    method: 'POST',
                    success: function (res) {
                      console.log(res.data);
                    }
                  });
                }
              })
            }
          })
        } else {
          // 用户未授权,需要显示授权弹窗
          wx.authorize({
            scope: 'scope.userInfo',
            success: () => {
              // 用户完成授权,可以继续获取用户信息
              wx.getUserProfile({
                desc: '获取用户信息',
                success: res => {
                  // 获取用户信息
                  const userInfo = res.userInfo;
                  // 获取用户登录凭证
                  wx.login({
                    success: res => {
                      // 获取用户登录凭证
                      const code = res.code;
                      // 将 code 和 userInfo 发送到后台服务器进行处理
                      wx.request({
                        url: 'https://example.com/login.php',
                        data: {
                          code: code,
                          userInfo: userInfo
                        },
                        method: 'POST',
                        success: function (res) {
                          wx.setStorage({                        ​
                            key: "token",
                            ​data: res.data.token​
                          })
                          console.log(res.data);
                        }
                      });
                    }
                  })
                }
              })
            }
          })
        }
      }
    })
    复制代码

     

     

     

    接着,小程序前台应用将获取到的 code 发送给后台服务器进行登录验证。后台服务器需要使用微信提供的接口(例如 wx.login 和 wx.getUserInfo)通过 code 获取用户的唯一标识 OpenID 和会话密钥 session_key。然后将用户的 OpenID 和 session_key 存储到后台数据库中,并将一个自定义的 token 返回给小程序前端。php代码示例如下:

    复制代码
    $appid = 'your_appid'; 
    $appsecret = 'your_appsecret';
    $code = $_POST['code'];
    $url = "https://api.weixin.qq.com/sns/jscode2session?appid=$appid&secret=$appsecret&js_code=$code&grant_type=authorization_code";
    $result = file_get_contents($url); $data = json_decode($result, true); $openid = $data['openid']; $session_key = $data['session_key']; // 存储到数据库中 $db = new mysqli('localhost', 'username', 'password', 'database'); $sql = "INSERT INTO `user`(`openid`, `session_key`) VALUES ('{$openid}', '{$session_key}')"; $result = $db->query($sql);
    复制代码

    接下来,php根据openid和session_key再生成token,返还给前台小程序应用。

    复制代码
    function generateToken($openid, $session_key) {
      $header = [
        'typ' => 'JWT',
        'alg' => 'HS256'
      ];
      $payload = [
        'openid' => $openid,
        'iat' => time(),
        'exp' => time() + 3600
      ];
      $secret = 'my_secret_key';
    
      // 生成 JWT Token
      $base64UrlHeader = base64UrlEncode(json_encode($header));
      $base64UrlPayload = base64UrlEncode(json_encode($payload));
      $signature = hash_hmac('sha256', $base64UrlHeader . '.' . $base64UrlPayload, $secret, true);
      $base64UrlSignature = base64UrlEncode($signature);
      $token = $base64UrlHeader . '.' . $base64UrlPayload . '.' . $base64UrlSignature;
    
      return $token;
    }
    
    function base64UrlEncode($data) {
      $urlSafeData = strtr(base64_encode($data), '+/', '-_');
      return rtrim($urlSafeData, '=');
    }
    
    $token = generateToken($openid, $session_key);
    
    echo json_encode(['token' => $token]);
    复制代码

    前台小程序应用接收到后台返回的token后,将其存储在小程序的本地缓存中,以后每次用户打开小程序时,我们可以从本地缓存中读取token并发送给后台进行验证。

    如下示例:

    复制代码
    // 获取本地缓存中的token
    const token = wx.getStorageSync('token');
    
    // 如果本地缓存中存在token,则向后台发送请求获取用户信息
    if (token) {
      wx.request({
        url: 'https://example.com/userinfo',
        header: {
          'Authorization': `Bearer ${token}`
        },
        success: res => {
          // 处理响应结果
          console.log(res.data);
        }
      });
    } else {
      // 如果本地缓存中不存在token,则说明用户还未登录,需要重新登录获取token
      wx.login({
        success: res => {
          // 向后台发送code,获取token
          wx.request({
            url: 'https://example.com/login',
            data: {
              code: res.code
            },
            success: res => {
              // 将后台返回的token存储到本地缓存中
              wx.setStorageSync('token', res.data.token);
              // 向后台发送请求获取用户信息
              wx.request({
                url: 'https://example.com/userinfo',
                header: {
                  'Authorization': `Bearer ${res.data.token}`
                },
                success: res => {
                  // 处理响应结果
                  console.log(res.data);
                }
              });
            }
          });
        }
      });
    }
    复制代码

    php后台获取到前台发来的请求及token后,就直接根据token来验证用户,如下代码所示:

    复制代码
    php
    use \Firebase\JWT\JWT;
    
    // JWT secret key
    $secret_key = "your_secret_key";
    
    // Token received from front-end  $secret_key和$token如存在数据库中,则从数据库中获取 
    $token = "token_received_from_front_end";
    
    try {
        // Decode token and get the payload
        $payload = JWT::decode($token, $secret_key, array('HS256'));
        
        // You can now access the token payload data
        $user_id = $payload->user_id;
        $username = $payload->username;
        // ...
    
        // Token is valid
        echo "Token is valid!";
    } catch (Exception $e) {
        // Token is invalid
        echo "Token is invalid: " . $e->getMessage();
    }
    ?>
    复制代码

    如此,则完成整个登录验证机制的实现。

     
  • 相关阅读:
    .NET 中 Channel 类简单使用
    微软新型云计算——利用xarray-spatialDEM进行分类(重分类)
    3年Java经验,这份大厂面试进阶手册帮我重新梳理了职业生涯
    Python 插入、替换、提取、或删除Excel中的图片
    网络-HTTPS
    支持JDK19虚拟线程的web框架,之四:看源码,了解quarkus如何支持虚拟线程
    随机油漆 (SPO)优化算法(Matlab代码实现)
    【LeetCode-112】路径总和
    android studio修改字体大小
    【深入浅出向】从自信息到熵、从相对熵到交叉熵,nn.CrossEntropyLoss, 交叉熵损失函数与softmax,多标签分类
  • 原文地址:https://www.cnblogs.com/eminer/p/17179508.html