uniapp微信小程序授权登录并获取手机号的方法
作者:Mr阿斌
这篇文章主要给大家介绍了关于uniapp微信小程序授权登录并获取手机号的相关资料,我们在uniapp开发微信小程序的过程中,经常需要在微信端登录,需要的朋友可以参考下
新版:前端要授权两次,一次获取用户信息授权码code,另外一次获取用户手机授权码code,全部传给后端。后端通过用户信息授权码获取openid,通过手机授权码获取手机号码。老版:前端传给后端授权码code和用户手机授权回调 里的iv和encryptedData给后端,后端通过code获取openid和sessionKey,然后他用sessionKey和iv解密encryptedData获取手机号。最后通过手机号进行绑定用户,然后通过登录验证返回给前端登录凭证token。
登录逻辑
新版
1.调用uni.login()获取code1
2.用户主动触发button按钮在回调getPhoneNumber获取code2
<button open-type="getPhoneNumber" bindgetphonenumber="getPhoneNumber"></button> Page({ getPhoneNumber (e) { console.log(e.detail.code) } })
3.后端拿到code1获取openid ,code2获取手机号码(代码在api里面)
老版
1.先在onshow()生命周期中获取code
2.用户主动触发button按钮在回调getPhoneNumber获取iv和encryptedData
<button open-type="getPhoneNumber" bindgetphonenumber="getPhoneNumber"></button> Page({ getPhoneNumber (e) { console.log(e.detail.errMsg) console.log(e.detail.iv) console.log(e.detail.encryptedData) } })
3.后端拿到code、iv、encryptedData,然后code获取openid和sessionKey,然后通过sessionKey和iv解密encryptedData获取到手机号
获取得到的解密数据为以下 json 结构: { "phoneNumber": "13580006666", "purePhoneNumber": "13580006666", "countryCode": "86", "watermark": { "appid":"APPID", "timestamp": TIMESTAMP } }
解密工具类
package hry.project.cdwjs.wxLogin; import org.apache.commons.codec.binary.Base64; import org.bouncycastle.jce.provider.BouncyCastleProvider; import javax.crypto.Cipher; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import java.nio.charset.StandardCharsets; import java.security.*; /** * @author qyb * @version 1.0 * @date 2023/3/13-9:38 */ public class WxDecryptUtills { public static boolean initialized = false; /** * Adds a provider to the next position available. */ public static void initialize() { if (initialized) return; // Construct a new provider. This should only be required when // using runtime registration of the provider using the Security.addProvider(new BouncyCastleProvider()); initialized = true; } // iv处理 public static AlgorithmParameters generateIV(byte[] iv) throws Exception{ AlgorithmParameters params = AlgorithmParameters.getInstance("AES"); params.init(new IvParameterSpec(iv)); return params; } /** * AES解密 * @param content 密文 * @param keyByte sessionKey * @param ivByte iv * @return 解密json数据 */ public static byte[] decrypt(byte[] content, byte[] keyByte, byte[] ivByte) { initialize(); try { Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding"); Key sKeySpec = new SecretKeySpec(keyByte, "AES"); // cipher 初始化 cipher.init(Cipher.DECRYPT_MODE, sKeySpec, generateIV(ivByte)); return cipher.doFinal(content); } catch (Exception e) { e.printStackTrace(); } return null; } /** * 微信小程序用户信息解密 * @param encryptedData 加密数据 * @param sessionKey 会话密钥 * @param iv 向量 * @return {@link String} */ public static String decrypt(String encryptedData, String sessionKey, String iv){ try { byte[] resultByte = decrypt(Base64.decodeBase64(encryptedData), Base64.decodeBase64(sessionKey), Base64.decodeBase64(iv)); if(null != resultByte && resultByte.length > 0){ return new String(resultByte, StandardCharsets.UTF_8); } } catch (Exception e) { e.printStackTrace(); } return null; } }
api
package hry.project.cdwjs.wxLogin.impl; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import hry.bean.JsonResult; import hry.business.cu.model.CuCustomer; import hry.business.cu.service.CuCustomerService; import hry.project.cdwjs.wxLogin.WxDecryptUtills; import hry.project.cdwjs.wxLogin.WxLoginService; import hry.project.cdwjs.wxLogin.WxLoginVo; import hry.redis.RedisService; import hry.security.jwt.JWTToken; import hry.security.jwt.JWTUtil; import hry.utils.HttpUtils; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import java.util.HashMap; /** * @author qyb * @version 1.0 * @date 2023/3/9-17:38 */ @Service @Slf4j public class WxLoginServiceImpl implements WxLoginService { @Value("${wxLogin.appId}") private String appId; @Value("${wxLogin.appSecret}") private String appSecret; @Autowired private CuCustomerService cuCustomerService; @Autowired private RedisService redisService; /** * 获取accesstoken * * @return */ private String getAccessToken() { String accessToken = ""; String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + appId + "&secret=" + appSecret; try { String resultString = HttpUtils.get(url); log.info("获取微信accessToken:{}", resultString); if (StringUtils.isNotEmpty(resultString)) { JSONObject jsonObject = JSON.parseObject(resultString); accessToken = jsonObject.get("access_token").toString(); } else { log.error("返回值为空,请检查请求报文或者请求地址是否正确"); } } catch (Exception e) { e.printStackTrace(); } return accessToken; } /** * 获取手机号 */ private String getPhoneNumber(String code) { String phoneNumber = ""; String url = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=" + getAccessToken(); HashMap<String, String> params = new HashMap<>(); params.put("code", code); try { String resultString = HttpUtils.postByQuery(url, params, null); log.info("获取微信手机号码:{}", resultString); if (StringUtils.isNotEmpty(resultString)) { JSONObject jsonObject = JSON.parseObject(resultString); JSONObject phone_info = jsonObject.getJSONObject("phone_info"); phoneNumber = phone_info.getString("phoneNumber"); } else { log.error("返回值为空,请检查请求报文或者请求地址是否正确"); } } catch (Exception e) { e.printStackTrace(); } return phoneNumber; } /** * 获取openId */ private String getOpenId(String code) { String url = "https://api.weixin.qq.com/sns/jscode2session?appid=" + appId + "&secret=" + appSecret + "&js_code=" + code + "&grant_type=authorization_code"; try { String resultString = HttpUtils.get(url); log.info("获取微信openId:{}", resultString); if (StringUtils.isNotEmpty(resultString)) { return resultString; } else { log.error("返回值为空,请检查请求报文或者请求地址是否正确"); } } catch (Exception e) { e.printStackTrace(); } return ""; } @Override public JsonResult loginByWx(WxLoginVo wxLoginVo) { String res = this.getOpenId(wxLoginVo.getUserInfoCode()); JSONObject jsonObject = JSONObject.parseObject(res); String openId = jsonObject.getString("openid"); String sessionKey = jsonObject.getString("session_key"); if (StringUtils.isEmpty(openId)) { return new JsonResult().setMsg("未获取到openId,登录失败"); } String data = WxDecryptUtills.decrypt(wxLoginVo.getEncryptData(), sessionKey, wxLoginVo.getIv()); JSONObject jsonObject1 = JSONObject.parseObject(data); String phoneNumber =jsonObject1.getString("phoneNumber"); if (StringUtils.isEmpty(phoneNumber)) { return new JsonResult().setMsg("未获取到手机号,登录失败"); } CuCustomer cuCustomer = cuCustomerService.checkMobile(phoneNumber); if (cuCustomer == null) { // 注册 cuCustomer = cuCustomerService.regist3(openId, phoneNumber, wxLoginVo.getNickname(), wxLoginVo.getAvatar()); } else { // 写入微信openid if (StringUtils.isEmpty(cuCustomer.getWxOpenId())) { cuCustomer.setWxOpenId(openId); } cuCustomer.setWxAvatar(wxLoginVo.getAvatar()); cuCustomerService.update(cuCustomer); } // 登录 String token = JWTUtil.sign(phoneNumber, JWTToken.SOURCE_PC, JWTToken.TYPE_CUSTOMER, cuCustomer.getPassword()); redisService.save(JWTUtil.getCustomerRefreshTimeKey(token), JSON.toJSONString(cuCustomer), JWTUtil.REFRESH_TIME); redisService.save(JWTUtil.getCustomerUserKey(token), JSON.toJSONString(cuCustomer), JWTUtil.EXPIRE_TIME); //防止用户多端登录,产生多个token String oldTokenStr = redisService.get("LOGINCUCUSTOMER:" + cuCustomer.getId()); if (StringUtils.isNotEmpty(oldTokenStr)) { JWTToken oldToken = new JWTToken(oldTokenStr); redisService.delete("JWT:token:" + oldToken.getSource() + ":" + oldToken.getType() + ":refreshTime:" + oldToken.getSignId()); redisService.delete("JWT:token:" + oldToken.getSource() + ":" + oldToken.getType() + ":user:" + oldToken.getSignId()); } redisService.save("LOGINCUCUSTOMER:" + cuCustomer.getId(), token); HashMap<String, Object> map = new HashMap<>(); map.put("token", token); return new JsonResult().setSuccess(true).setObj(map); } }
注意:老版调用过程中一定要先调用uni.login(),再去触发button获取手机号,不然会导致sessionKey失效,从而使得后端解密失败。
总结
到此这篇关于uniapp微信小程序授权登录并获取手机号的文章就介绍到这了,更多相关uniapp微信小程序授权登录内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!