详解小步伐常见的登录方式

打印 上一主题 下一主题

主题 528|帖子 528|积分 1584

1. 小步伐登录

小步伐有两种登录方式,一种基于手机号码进行登录,另一种是利用用户在公众号下的唯一标识(openid)进行登录(小步伐是公众号的一种).
接下来先解说下,基于 openid 登录。
1.1 基于 openid 登录

先看下图,形貌通过微信小步伐提供的 code 换取当前用户在小步伐中的唯一标识,详细流程可以参数下图:

接下来通过代码实现下大概流程:


  • 获取 code
  1. uni.login({
  2.   success: async (res) => {
  3.     if (res.errMsg === 'login:ok') {
  4.       const { data } = await login({
  5.         code: res.code,
  6.       });
  7.       // 保存用户信息
  8.     }
  9.   },
  10.   fail(e) {
  11.     uni.showToast({
  12.       title: e.message,
  13.     });
  14.   },
  15. });
复制代码


  • 服务端接收 code 去微信后台换取对应 openid
  1. // nodejs 部分代码
  2. const { appid, secret, grant_type } = require('../config/wx');
  3. router.post('/login', (req, res) => {
  4.   const { code } = req.query;
  5.   const { appid, secret, grant_type } = require('../config/wx');
  6.   const { openid } = await request.get('/sns/jscode2session', {
  7.     appid,
  8.     secret,
  9.     js_code: code,
  10.     grant_type,
  11.   });
  12. });
复制代码


  • 在数据库中查找对应 openid 是否存在
  1. const { appid, secret, grant_type } = require('../config/wx');
  2. router.post('/login', (req, res) => {
  3.   // 1. 获取 code
  4.   const { code } = req.query;
  5.   // 2. 通过 code 获取 openid 和 session_key
  6.   const { openid } = await request.get('/sns/jscode2session', {
  7.     appid,
  8.     secret,
  9.     js_code: code,
  10.     grant_type,
  11.   });
  12.   // 3. 查找用户是否已经注册
  13.   models.user
  14.     .findOne({
  15.       where: {
  16.         openid,
  17.       },
  18.     })
  19.     .then((user) => {
  20.       if (user) {
  21.         // 3.2 如果用户已经注册,返回用户信息
  22.         res.json(
  23.           new Result({
  24.             data: user,
  25.             msg: '登录成功',
  26.           })
  27.         );
  28.       } else {
  29.         // 3.3 如果用户没有注册,创建用户并返回用户信息
  30.         const username = randomUserName();
  31.         models.user
  32.           .create({
  33.             nickname: username,
  34.             openid,
  35.             avatar: '/uploads/default-avatar.png',
  36.           })
  37.           .then((user) => {
  38.             res.json(
  39.               new Result({
  40.                 data: user,
  41.                 msg: '登录成功',
  42.               })
  43.             );
  44.           });
  45.       }
  46.     });
  47. });
复制代码
上面就是一个基于 code 获取 openid,并通过 openid 创建新的用户,并将创建好的用户返回。
为了方便明白,这里简化形貌了登录逻辑。在现实业务代码中,通常会利用 openid 、 session key 和用户信息来创建自定义登录凭据(token),并在登录时将用户信息和 token 一起返回给前端。前端会将 token 存储在本地,并在下一次需要登录的业务请求中携带 token,从而实现业务鉴权的功能。这种方式通常利用 JWT(JSON Web Token)等工具来实现。在后续的解说中,我们将详细先容这些概念和技术细节。
1.2 手机号码快捷登录

获取手机号码的前提:


  • 非个人小步伐
  • 认证的小步伐
  • 非海外的企业认证
下面是大概业务流程图:

1.2.1 获取对应 code

  1. <template>
  2.   <button
  3.     class="login-btn"
  4.     open-type="getPhoneNumber"
  5.     @getphonenumber="getPhoneNumber"
  6.   >
  7.     手机号码登录
  8.   </button>
  9. </template>
  10. <script>
  11. export default {
  12.   setup() {
  13.     // 目前该接口针对非个人开发者,且完成了认证的小程序开放(不包含海外主体)
  14.     const getPhoneNumber = (e) => {
  15.       const { code, errMsg } = e.detail;
  16.       if (errMsg === 'getPhoneNumber:ok') {
  17.         const { data } = await loginByPhone({
  18.           code,
  19.         });
  20.       } else {
  21.         uni.showToast({
  22.           title: errMsg,
  23.         });
  24.       }
  25.     };
  26.     return {
  27.       getPhoneNumber,
  28.     };
  29.   },
  30. };
  31. </script>
复制代码
1.2.2 后端处置惩罚逻辑

  1. // 基于手机号登录
  2. router.post('/loginByPhone', async function (req, res) {
  3.   try {
  4.     // 1. 获取 code 和 loginCode
  5.     const { code } = req.body;
  6.     // 2. 获取接口调用凭据,理论上这里需要缓存 access_token,避免频繁调用接口
  7.     const { access_token } = await request.get('/cgi-bin/token', {
  8.       grant_type: 'client_credential',
  9.       appid,
  10.       secret,
  11.     });
  12.     // 3. 获取手机号
  13.     const { phone_info } = await request.post(
  14.       `/wxa/business/getuserphonenumber?access_token=${access_token}`,
  15.       {
  16.         code,
  17.       }
  18.     );
  19.     // 4. 查找用户是否已经注册
  20.     // 4.1 根据 phone 查找用户
  21.     const { purePhoneNumber } = phone_info;
  22.     models.user
  23.       .findOne({
  24.         where: {
  25.           purePhoneNumber,
  26.         },
  27.       })
  28.       .then((user) => {
  29.         if (user) {
  30.           // 4.2 如果用户已经注册,返回用户信息
  31.           res.json(
  32.             new Result({
  33.               data: user,
  34.               msg: '登录成功',
  35.             })
  36.           );
  37.         } else {
  38.           // 4.3 如果用户没有注册,创建用户并返回用户信息
  39.           const username = randomUserName();
  40.           models.user
  41.             .create({
  42.               nickname: username,
  43.               avatar: '/uploads/default-avatar.png',
  44.               phone: phone_info.purePhoneNumber,
  45.             })
  46.             .then((user) => {
  47.               res.json(
  48.                 new Result({
  49.                   data: user,
  50.                   msg: '登录成功',
  51.                 })
  52.               );
  53.             });
  54.         }
  55.       });
  56.   } catch (error) {
  57.     res.json(
  58.       new Result({
  59.         code: 'BIZ_ERROR',
  60.         msg: error.errmsg || error.message,
  61.       })
  62.     );
  63.   }
  64. });
复制代码
上面代码,实现获取手机号码并利用手机号码作为唯一标识,进行用户创建和查找的操作。
从登录的角度来看,利用手机号码作为唯一标识符是没有问题的。然而,如果用户实验利用非手机号码(例如 OpenID)进行登录,并在数据库中找不到匹配的记录时,系统会创建一个新的账号。这大概导致同一个用户在系统中存在多个账号的情况。
为了优化这种情况,可以思量以下几种方法:


  • 当用户利用 openid 登录后,检测未绑定手机号码时,进行号码绑定
  • 当用户利用手机号码登录时,提前调用 wx.login 获取对应 code,换取 openid 把他与手机号码进行关联
现在基于上面的代码,接纳第二种方案,只需要微调下代码就能办理这个问题。


  • 登录时把 wx.login 获取 code 通报给后端
  1. <template>
  2.   <button
  3.     class="login-btn"
  4.     open-type="getPhoneNumber"
  5.     @getphonenumber="getPhoneNumber"
  6.   >
  7.     手机号码登录
  8.   </button>
  9. </template>
  10. <script>
  11. export default {
  12.   setup() {
  13.     // 目前该接口针对非个人开发者,且完成了认证的小程序开放(不包含海外主体)
  14.     const getPhoneNumber = (e) => {
  15.       const { code, errMsg } = e.detail;
  16.       if (errMsg === 'getPhoneNumber:ok') {
  17.         uni.login({
  18.           success: async (res) => {
  19.             if (res.errMsg === 'login:ok') {
  20.               const { data } = await loginByPhone({
  21.                 code,
  22.                 loginCode: res.code,
  23.               });
  24.               userStore.setUserInfo(data);
  25.               uni.navigateBack();
  26.             }
  27.           },
  28.           fail(e) {
  29.             uni.showToast({
  30.               title: e.message,
  31.             });
  32.           },
  33.         });
  34.       } else {
  35.         uni.showToast({
  36.           title: errMsg,
  37.         });
  38.       }
  39.     };
  40.     return {
  41.       getPhoneNumber,
  42.     };
  43.   },
  44. };
  45. </script>
复制代码


  • 服务端基于 loginCode 换取 openid
  1. // 基于手机号登录
  2. router.post('/loginByPhone', async function (req, res) {
  3.   try {
  4.     // 1. 获取 code 和 loginCode
  5.     const { code, loginCode } = req.body;
  6.     // 2. 获取接口调用凭据,理论上这里需要缓存 access_token,避免频繁调用接口
  7.     const { access_token } = await request.get('/cgi-bin/token', {
  8.       grant_type: 'client_credential',
  9.       appid,
  10.       secret,
  11.     });
  12.     // 3. 获取 openid
  13.     const { openid } = await request.get('/sns/jscode2session', {
  14.       appid,
  15.       secret,
  16.       js_code: loginCode,
  17.       grant_type,
  18.     });
  19.     // 4. 获取手机号
  20.     const { phone_info } = await request.post(
  21.       `/wxa/business/getuserphonenumber?access_token=${access_token}`,
  22.       {
  23.         code,
  24.         openid,
  25.       }
  26.     );
  27.     // 5. 查找用户是否已经注册
  28.     // 5.1 根据 openid 查找用户
  29.     models.user
  30.       .findOne({
  31.         where: {
  32.           openid,
  33.         },
  34.       })
  35.       .then((user) => {
  36.         if (user) {
  37.           // 5.2 如果用户已经注册,返回用户信息
  38.           res.json(
  39.             new Result({
  40.               data: user,
  41.               msg: '登录成功',
  42.             })
  43.           );
  44.         } else {
  45.           // 5.3 如果用户没有注册,创建用户并返回用户信息
  46.           const username = randomUserName();
  47.           models.user
  48.             .create({
  49.               nickname: username,
  50.               openid,
  51.               avatar: '/uploads/default-avatar.png',
  52.               phone: phone_info.purePhoneNumber,
  53.             })
  54.             .then((user) => {
  55.               res.json(
  56.                 new Result({
  57.                   data: user,
  58.                   msg: '登录成功',
  59.                 })
  60.               );
  61.             });
  62.         }
  63.       });
  64.   } catch (error) {
  65.     res.json(
  66.       new Result({
  67.         code: 'BIZ_ERROR',
  68.         msg: error.errmsg || error.message,
  69.       })
  70.     );
  71.   }
  72. });
复制代码
这种方案被视为最佳的办理方案,可以或许有效办理多账号和绑定手机号码等问题。 现实上,接纳哪种方式取决于详细的业务场景,因为在某些情况下,用户大概会担心手机号码泄漏而不愿接纳这种方式。
1.2.3 留意



  • 获取手机号码是需要收费,每次调用需要 0.03 元。
  • wx.login 与 getPhoneNumber 中获取的 code 不是同一个
总结



  • 基于 openid 或 手机号码快捷登录
  • 获取手机号码前置条件
  • 怎样办理多账号的问题
  • 解说前端、后端、微信登录过程中完备交互流程,方便更好去明白小步伐登录
如果您有任何疑问,请随时在批评区留言。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

河曲智叟

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表