【尚医通】微信扫码登录和手机号登录冲突问题解决思路
问题描述
最近做尚医通遇到一个问题,微信扫码登录和手机号登录在 特殊情况
下会发生冲突,导致无法登录的问题。下面就描述一下几种情况。
正常情况:用户第一次一上来就使用微信扫码登录,后端在调用回调函数的时候就完成了用户注册,由于是第一次登录,需要绑定手机号,于是又调用了一次手机号登录的接口,手机号登录成功之后就完成了绑定。之后就可以随便使用扫码登录或手机号登录了。
特殊情况:用户第一次一上来就使用手机号登录,后端会根据手机号去数据库搜索“唯一”的一条数据,如果结果为空则说明是第一次登录,直接注册;如果不为空,说明已经注册过,就直接登录。用户第二次登录时使用的是微信扫码登录,后端在调用回调函数的时候再次完成用户注册,然后又绑定手机号。那么现在数据库就有两条手机号相同的数据了。第三次登陆时若使用手机号登录,那么“唯一”查询就不满足了,就会报错,最后登录不了。
回顾流程
首先回顾一下扫码登录的流程。
更多详情请见:资源中心 - 微信开放平台 (qq.com)
解决思路
上回调函数代码!
@GetMapping("/callback")
public String callback(@RequestParam("code") String code, @RequestParam("state") String state) {
log.info("code:{}", code);
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);
try {
String accesstokenInfo = HttpClientUtils.get(accessTokenUrl);
log.info("accesstokenInfo:{}", accesstokenInfo);
JSONObject jsonObject = JSON.parseObject(accesstokenInfo);
String access_token = jsonObject.getString("access_token");
String openid = jsonObject.getString("openid");
log.info("access_token:{}", access_token);
log.info("openid:{}", openid);
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);
String nickname = resultUserInfoJson.getString("nickname");
String headimgurl = resultUserInfoJson.getString("headimgurl");
UserInfo userInfo = userInfoService.saveUser(nickname, openid);
String name = userInfo.getName();
if (StringUtils.isEmpty(name)) {
name = userInfo.getNickName();
}
if (StringUtils.isEmpty(name)) {
name = userInfo.getPhone();
}
if (StringUtils.isEmpty(userInfo.getPhone())) {
openid = userInfo.getOpenid();
} else {
openid = "";
}
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;
}
}
问题主要出现在第七步。
解决思路如下:
- 如果数据库中已经存在了手机号登录时的数据,那么微信登录时就不应该再向数据库中添加数据。
- 但是在回调函数中我们无法通过手机号查询数据库。所以我们无法在回调函数中实现是否注册的判断,那不如索性把第七步给删了,改成只搜索用户信息,不保存用户信息。
回调函数中无法一口气解决所有的问题,所以我们只得把重心调转到登录方法上。
上登录方法代码!!!:
@Override
public Map<String, Object> loginUser(LoginVo loginVo) {
String phone = loginVo.getPhone();
String code = loginVo.getCode();
if (StringUtils.isBlank(phone) || StringUtils.isBlank(code)) {
throw new YyghException(ResultCodeEnum.PARAM_ERROR);
}
String redisCode = redisTemplate.opsForValue().get(phone);
if (!code.equals(redisCode)) {
throw new YyghException(ResultCodeEnum.CODE_ERROR);
}
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);
}
}
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);
}
}
if (userInfo.getStatus() == 0) {
throw new YyghException(ResultCodeEnum.LOGIN_DISABLED_ERROR);
}
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);
String token = JwtHelper.createToken(userInfo.getId(), name);
map.put("token", token);
return map;
}
我们重写第4步代码。
解决思路如下:
在第4步绑定手机号的时候,我们先根据手机号把用户给查询出来。
- 如果用户存在且还没设置openid,那么我们就将前端传过来的openid设置给该用户,完成绑定;
- 如果用户存在且也已经设置了openid,那么我们直接抛一个异常,提示前端该手机已经绑定了微信号。
- 如果用户不存在,那么我们利用openid,phone直接注册一个新用户并登录,实现注册,绑定,登录一条龙。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)