• PHP做app扫码登录的一些步骤和代码片段记录一下


    总体的思路步骤大致如下:

    1. 生成一个唯一值,返回给前端页面用来生成唯一值;
    2. 前端轮询接口,直到返回二维码过期或者扫码成功;
    3. app端进行扫码,并对二维码的值进行判断;
    4. 二维码值错误,返回错误信息;
    5. 二维码正确,让用户选择是否登录,请求后端接口,写入数据库相应表(code表),状态标记为已扫码(状态有已扫码,登录,取消);
    6. 当用户选择登录,状态标记为登录,取消则标记为取消
    7. 前端轮询,根据不同的返回状态显示不同的提示信息,和app端同步,当用户选择登录的时候控制页面跳转,取消的时候刷新二维码开始新的轮询

    代码片段基于CRM Chat项目。项目地址CRMChat: TP6+swoole4开源客服系统,支持微信网页、H5端、PC端客服接入,商家端有PC端管理、H5端、App端接待,支持用户添加标签、分组等功能,前后端所有代码全部开源

    1、从后端获取一个唯一的key值,让前端带着这个key组成链接,生成二维码

    1. /**
    2. * 获取登录唯一code
    3. * @return mixed
    4. */
    5. public function getLoginKey()
    6. {
    7. $key = md5(time() . uniqid());
    8. $time = time() + 600;
    9. CacheService::set($key, 1, 600);
    10. return $this->success(['key' => $key, 'time' => $time]);
    11. }
    1. // 获取客服扫码key
    2. getSanCodeKey() {
    3. getSanCodeKey().then(res => {
    4. this.codeKey = res.data.key
    5. this.creatQrCode()
    6. this.scanTime = setInterval(() => {
    7. this.timeNum++
    8. if(this.timeNum >= 60) {
    9. this.timeNum = 0
    10. window.clearInterval(this.scanTime)
    11. this.rxpired = true
    12. } else {
    13. this.getScanStatus()
    14. }
    15. }, 1000)
    16. }).catch(error => {
    17. this.timeNum = 0
    18. window.clearInterval(this.scanTime)
    19. this.rxpired = true
    20. this.$Message.error(error.msg)
    21. })
    22. },

    2、前端轮询接口二维码扫码结果接口

    1. // 扫码登录情况
    2. getScanStatus() {
    3. scanStatus(this.codeKey).then(async res => {
    4. // 0 = 二维码过期需要重新获取授权凭证
    5. if(res.data.status == 0) {
    6. this.timeNum = 0
    7. window.clearInterval(this.scanTime)
    8. this.rxpired = true
    9. }
    10. // 1=正在扫描
    11. if(res.data.status == 1) {
    12. }
    13. // 3 扫描成功正在登录
    14. if(res.data.status == 3) {
    15. window.clearInterval(this.scanTime)
    16. let expires = this.getExpiresTime(res.data.exp_time);
    17. // 记录用户登陆信息
    18. setCookies('kefu_uuid', res.data.kefuInfo.uid, expires);
    19. setCookies('kefu_token', res.data.token, expires);
    20. setCookies('kefu_expires_time', res.data.exp_time, expires);
    21. setCookies('kefuInfo', res.data.kefuInfo, expires);
    22. // 记录用户信息
    23. this.$store.commit('kefu/setInfo', res.data.kefuInfo)
    24. if(this.$store.state.media.isMobile) {
    25. //手机页面
    26. return this.$router.replace({ path: this.$route.query.redirect || '/kefu/mobile_list' });
    27. } else {
    28. // pc页面
    29. return this.$router.replace({ path: this.$route.query.redirect || '/kefu/pc_list' });
    30. }
    31. }
    32. }).catch(error => {
    33. this.$Modal.error({
    34. title: '提示',
    35. content: error.msg
    36. });
    37. this.timeNum = 0
    38. window.clearInterval(this.scanTime)
    39. this.rxpired = true
    40. })
    41. },

    3、app端扫描二维码,扫码后跳转到确定授权页面

    1. // 扫描二维码
    2. handleScanCode() {
    3. // let str = "http://192.168.31.192:8081/pages/users/scan_login/index?key=463aca66113f65396dc28e3f0041a2f2";
    4. uni.scanCode({
    5. onlyFromCamera: true, // 是否只允许相机扫码,不允许相机选择图片
    6. success(res) {
    7. console.log(res);
    8. navigateTo(1, '/pages/view/authorizedLogin/index', {
    9. key: res.result.split('=')[1]
    10. });
    11. },
    12. fail: () => {}
    13. });
    14. },

     

    4、取消则返回上一页,确定就带着code值请求后端,首先进行一系列的判断code,然后在标记该用户的uuid值。kefuId是在中间件传过来的(该项目使用的jwt 认证)。最后改变二维码状态是扫码中。

    1. /**
    2. * 确认登录
    3. * @param Request $request
    4. * @param string $code
    5. * @return mixed
    6. */
    7. public function setLoginCode(Request $request)
    8. {
    9. $code = $request->post('code');
    10. if (!$code) {
    11. return app('json')->fail('登录CODE不存在');
    12. }
    13. $cacheCode = CacheService::get($code);
    14. if ($cacheCode === false || $cacheCode === null) {
    15. return app('json')->fail('二维码已过期请重新扫描');
    16. }
    17. $userInfo = $this->services->get(['id' => $request->kefuId()]);
    18. if (!$userInfo) {
    19. return app('json')->fail('您不是客服无法登录');
    20. }
    21. $userInfo->uniqid = $code;
    22. $userInfo->save();
    23. CacheService::set($code, '0', 600);
    24. return app('json')->success('登录成功');
    25. }

    中间件:

    1. use app\Request;
    2. use app\services\kefu\LoginServices;
    3. use crmeb\interfaces\MiddlewareInterface;
    4. use think\facade\Config;
    5. /**
    6. * Class KefuAuthTokenMiddleware
    7. * @package app\kefu\middleware
    8. */
    9. class KefuAuthTokenMiddleware implements MiddlewareInterface
    10. {
    11. /**
    12. * @param Request $request
    13. * @param \Closure $next
    14. * @throws \Psr\SimpleCache\InvalidArgumentException
    15. * @throws \think\db\exception\DataNotFoundException
    16. * @throws \think\db\exception\DbException
    17. * @throws \think\db\exception\ModelNotFoundException
    18. */
    19. public function handle(Request $request, \Closure $next)
    20. {
    21. $authInfo = null;
    22. $token = trim(ltrim($request->header(Config::get('cookie.token_name', 'Authori-zation')), 'Bearer'));
    23. /** @var LoginServices $services */
    24. $services = app()->make(LoginServices::class);
    25. $kefuInfo = $services->parseToken($token);
    26. Request::macro('kefuId', function () use (&$kefuInfo) {
    27. return (int)$kefuInfo['id'];
    28. });
    29. Request::macro('kefuInfo', function () use (&$kefuInfo) {
    30. return $kefuInfo;
    31. });
    32. return $next($request);
    33. }
    34. }

    5、后端返回二维码扫码结果

    1. /**
    2. * 检测有没有人扫描登录
    3. * @param string $key
    4. * @return array|int[]
    5. * @throws InvalidArgumentException
    6. * @throws DataNotFoundException
    7. * @throws DbException
    8. * @throws ModelNotFoundException
    9. */
    10. public function scanLogin(string $key)
    11. {
    12. $hasKey = CacheService::has($key);
    13. if ($hasKey === false) {
    14. $status = 0;//不存在需要刷新二维码
    15. } else {
    16. $keyValue = CacheService::get($key);
    17. if ($keyValue === '0') {
    18. $status = 1;//正在扫描中
    19. $kefuInfo = $this->dao->get(['uniqid' => $key], ['account', 'uniqid']);
    20. if ($kefuInfo) {
    21. $tokenInfo = $this->authLogin($kefuInfo->account);
    22. $tokenInfo['status'] = 3;
    23. $kefuInfo->uniqid = '';
    24. $kefuInfo->save();
    25. CacheService::delete($key);
    26. return $tokenInfo;
    27. }
    28. } else {
    29. $status = 2;//没有扫描
    30. }
    31. }
    32. return ['status' => $status];
    33. }

    6、扫描确认成功,保存用户信息,跳转页面

  • 相关阅读:
    竞赛 深度学习YOLOv5车辆颜色识别检测 - python opencv
    牛客前端刷题(四)——微信小程序篇
    NZ系列工具NZ02:VBA读取PDF使用说明
    java正则表达式教程
    Linux 之文件查找
    支持JDK19虚拟线程的web框架,之四:看源码,了解quarkus如何支持虚拟线程
    canvas画一个笑脸和画一个三角形
    Aria2 for Mac (免HomeBrew)
    结构优化软件SolidThinking Inspire的自学攻略
    力扣45. 跳跃游戏 II
  • 原文地址:https://blog.csdn.net/W07028057/article/details/126466592