【尚医通】微信扫码登录和手机号登录冲突问题解决思路

【尚医通】微信扫码登录和手机号登录冲突问题解决思路

问题描述

最近做尚医通遇到一个问题,微信扫码登录手机号登录特殊情况 下会发生冲突,导致无法登录的问题。下面就描述一下几种情况。

正常情况:用户第一次一上来就使用微信扫码登录,后端在调用回调函数的时候就完成了用户注册,由于是第一次登录,需要绑定手机号,于是又调用了一次手机号登录的接口,手机号登录成功之后就完成了绑定。之后就可以随便使用扫码登录或手机号登录了。

特殊情况:用户第一次一上来就使用手机号登录,后端会根据手机号去数据库搜索“唯一”的一条数据,如果结果为空则说明是第一次登录,直接注册;如果不为空,说明已经注册过,就直接登录。用户第二次登录时使用的是微信扫码登录,后端在调用回调函数的时候再次完成用户注册,然后又绑定手机号。那么现在数据库就有两条手机号相同的数据了。第三次登陆时若使用手机号登录,那么“唯一”查询就不满足了,就会报错,最后登录不了。


回顾流程

首先回顾一下扫码登录的流程。

在这里插入图片描述

更多详情请见:资源中心 - 微信开放平台 (qq.com)

解决思路

上回调函数代码!

//微信扫描后回调的方法
    @GetMapping("/callback")
    public String callback(@RequestParam("code") String code, @RequestParam("state") String state) {
        //1.获取临时票据 code
        log.info("code:{}", code);
        //2.拿着code和微信id和密钥,请求微信固定地址,得到两个值
        //2.1使用code和appid以及appscrect换取access_token
        // %s表示一个占位符
        StringBuffer baseAccessTokenUrl = new StringBuffer()
                .append("https://api.weixin.qq.com/sns/oauth2/access_token")
                .append("?appid=%s")
                .append("&secret=%s")
                .append("&code=%s")
                .append("&grant_type=authorization_code");
        String accessTokenUrl = String.format(baseAccessTokenUrl.toString(),
                ConstantWxPropertiesUtil.WX_OPEN_APP_ID,
                ConstantWxPropertiesUtil.WX_OPEN_APP_SECRET,
                code);
        //3.使用httpclient请求这个地址
        try {
            String accesstokenInfo = HttpClientUtils.get(accessTokenUrl);
            log.info("accesstokenInfo:{}", accesstokenInfo);
            //4.从返回字符串中获取两个值 openid 和access_token
            JSONObject jsonObject = JSON.parseObject(accesstokenInfo);
            String access_token = jsonObject.getString("access_token");
            //openid为每个微信用户唯一
            String openid = jsonObject.getString("openid");
            log.info("access_token:{}", access_token);
            log.info("openid:{}", openid);
            //5.根据access_token获取微信用户的基本信息
            String baseUserInfoUrl = "https://api.weixin.qq.com/sns/userinfo" +
                    "?access_token=%s" +
                    "&openid=%s";
            String userInfoUrl = String.format(baseUserInfoUrl, access_token, openid);
            String resultInfo = HttpClientUtils.get(userInfoUrl);
            log.info("resultInfo:{}", resultInfo);
            JSONObject resultUserInfoJson = JSON.parseObject(resultInfo);
            //6.解析用户信息
            //6.1用户名称
            String nickname = resultUserInfoJson.getString("nickname");
            //6.2用户头像
            String headimgurl = resultUserInfoJson.getString("headimgurl");

            //7.如果第一次微信登录添加到数据库
            UserInfo userInfo = userInfoService.saveUser(nickname, openid);

            //8.返回name和token字符串
            String name = userInfo.getName();
            if (StringUtils.isEmpty(name)) {
                name = userInfo.getNickName();
            }
            if (StringUtils.isEmpty(name)) {
                name = userInfo.getPhone();
            }
            //判断userInfo是否有手机号,如果手机号为空,返回openid
            //如果手机号不为空,返回openid值是空字符串
            //前端根据“openid”判断:如果openid为空,已绑定手机号(不需要再绑定手机号),否则需要绑定手机号
            if (StringUtils.isEmpty(userInfo.getPhone())) {
                openid = userInfo.getOpenid();
            } else {
                openid = "";
            }
            //使用jwt生成token字符串
            String token = JwtHelper.createToken(userInfo.getId(), name);
            //跳转到前端页面
            return "redirect:" + ConstantWxPropertiesUtil.YYGH_BASE_URL
                    + "/weixin/callback?token=" + token + "&openid="
                    + openid + "&name=" + URLEncoder.encode(name, "utf-8");
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

问题主要出现在第七步。

解决思路如下:

  1. 如果数据库中已经存在了手机号登录时的数据,那么微信登录时就不应该再向数据库中添加数据。
  2. 但是在回调函数中我们无法通过手机号查询数据库。所以我们无法在回调函数中实现是否注册的判断,那不如索性把第七步给删了,改成只搜索用户信息,不保存用户信息

回调函数中无法一口气解决所有的问题,所以我们只得把重心调转到登录方法上。

上登录方法代码!!!:

//手机号登录接口
    @Override
    public Map<String, Object> loginUser(LoginVo loginVo) {
        //1.从loginVo获取输入的手机号和验证码
        String phone = loginVo.getPhone();
        String code = loginVo.getCode();
        //2.判断手机号和验证码是否为空
        if (StringUtils.isBlank(phone) || StringUtils.isBlank(code)) {
            throw new YyghException(ResultCodeEnum.PARAM_ERROR);
        }
        //3.判断手机验证码和输入的验证码是否一致
        String redisCode = redisTemplate.opsForValue().get(phone);
        if (!code.equals(redisCode)) {
            throw new YyghException(ResultCodeEnum.CODE_ERROR);
        }

        //4.绑定手机号
        UserInfo userInfo = null;
        if (!StringUtils.isBlank(loginVo.getOpenid())) {
            userInfo = this.selectWxInfoByOpenId(loginVo.getOpenid());
            if (null != userInfo) {
                userInfo.setPhone(loginVo.getPhone());
                updateById(userInfo);
            } else {
                throw new YyghException(ResultCodeEnum.DATA_ERROR);
            }
        }
        //5.如果userinfo为空,进行正常的手机登录
        if (userInfo == null) {
            //判断是否第一次登录:根据手机号查询数据库,如果不存在相同手机号就是第一次登录
            LambdaQueryWrapper<UserInfo> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(UserInfo::getPhone, phone);
            userInfo = baseMapper.selectOne(queryWrapper);
            if (userInfo == null) {
                //第一次登录,添加信息到数据库
                userInfo = new UserInfo();
                userInfo.setName("");
                userInfo.setPhone(phone);
                userInfo.setStatus(1);
                baseMapper.insert(userInfo);
            }
        }


        //6.校验是否禁用
        if (userInfo.getStatus() == 0) {
            throw new YyghException(ResultCodeEnum.LOGIN_DISABLED_ERROR);
        }
        //7.不是第一次,直接登录
        //返回登录信息
        //返回登录用户名
        //返回token信息
        Map<String, Object> map = new HashMap<>();
        String name = userInfo.getName();
        if (StringUtils.isBlank(name)) {
            name = userInfo.getNickName();
        }
        if (StringUtils.isBlank(name)) {
            name = userInfo.getPhone();
        }
        map.put("name", name);
        // token生成
        String token = JwtHelper.createToken(userInfo.getId(), name);
        map.put("token", token);
        return map;
    }

我们重写第4步代码。

解决思路如下:

在第4步绑定手机号的时候,我们先根据手机号把用户给查询出来。

  1. 如果用户存在且还没设置openid,那么我们就将前端传过来的openid设置给该用户,完成绑定;
  2. 如果用户存在且也已经设置了openid,那么我们直接抛一个异常,提示前端该手机已经绑定了微信号。
  3. 如果用户不存在,那么我们利用openid,phone直接注册一个新用户并登录,实现注册,绑定,登录一条龙。
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值