项目背景
使用uniapp开发微信小程序,避免不了微信登录。但自动微信2022年升级了api版本后,不再允许返回昵称和头像信息,所以才出现无感登录或授权手机号登录。实现方式大同小异。
java后端所需maven
1、小程序无感登录
前端实现代码:
onLoad() {
if (!uni.getStorageSync("token")) {
this.showLogin = true;
uni.login({
provider: 'weixin',
success: (loginRes) => {
this.code = loginRes.code;
//此处将code传入后端进行解析到openid,最终得到登录后的token缓存到本地即可
}
})
}
}
由于使用uni.login并不需要用户授权,所以能做到无感登录。
后端实现:
/**
微信登录工具类
**/
public class WechatGetUserInfoUtil {
public static final String APPID = "wxd5fc6c544e752529";
public static final String SECRET = "c2bf267226c0157c859da6934ee3c298";
/**
根据微信小程序登录获得的code获取用户信息
*/
public static Map<String, String> getWxLoginInfo(String code) {
String apiUrl = "https://api.weixin.qq.com/sns/jscode2session?appid=" + APPID + "&secret=" + SECRET + "&js_code=" + code + "&grant_type=authorization_code";
String responseBody = HttpUtil.get(apiUrl);
Map jsonObject = new Gson().fromJson(responseBody, Map.class);
Map<String, String> map = new HashMap<>();
map.put("openid", jsonObject.get("openid").toString());
map.put("session_key", jsonObject.get("session_key").toString());
return map;
}
}
通过以上方法可以对应的openid,然后通过openid可以得到用户信息,如果不存在用户信息,则创建一个用户即可。默认头像和随机数昵称值即可。
2、授权手机号登录
授权手机号登录相对于无感登录是相对复杂一点,但也还好。
前端:(ps:此处前端框架使用了uView,只是样式上有所变化)
<template>
<view>
<!-- 登录授权弹出层 -->
<u-popup :show="showLogin" mode="center" round="10rpx" @close="showLogin=false">
<view class="login_view">
<view class="content_view">
<image src="../../static/logo.png"></image>
<view>亲,授权手机号后才能正常使用相关功能</view>
</view>
<view class="btn_view">
<u-button type="primary" open-type="getPhoneNumber" @getphonenumber="login" color="#43ad47"
shape="circle" text="授权登录"></u-button>
</view>
</view>
</u-popup>
</view>
</template>
<script>
export default {
data() {
return {
showLogin: false,
code:''
}
},
onLoad() {
if (!uni.getStorageSync("token")) {
this.showLogin = true;
uni.login({
provider: 'weixin',
success: (loginRes) => {
this.code = loginRes.code;
}
})
}
},
methods: {
login(e) { //授权登录
let obj = {
iv: e.detail.iv,
encryptedData: e.detail.encryptedData,
code: this.code
}
if (e.detail.iv) {
wxlogin(obj).then(res => {
this.showLogin = false;
uni.setStorageSync('token', res.data.access_token);
uni.showToast({
title: "登录成功",
icon: "none",
duration: 2000
})
})
} else {
uni.$u.toast('授权失败,请联系管理员');
}
},
}
</script>
<style lang="scss">
.login_view {
width: 630rpx;
height: 400rpx;
.title_view {
font-size: 36rpx;
color: #333;
text-align: center;
padding: 20rpx;
}
.content_view {
margin: 50rpx;
margin-bottom: 20rpx;
font-size: 28rpx;
text-align: center;
image {
width: 100rpx;
height: 100rpx;
border-radius: 50%;
}
view {
margin-top: 20rpx;
}
}
.btn_view {
margin: 30rpx;
}
}
</style>
注意,获取手机号需要用户点击按钮触发后方可获取,不然是无法获取到手机号信息的。
获取code一定要在授权之前获取,否则后端无法解密出对应的手机号信息。
后端实现:
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import com.google.gson.Gson;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Base64Utils;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.*;
import java.security.spec.InvalidParameterSpecException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
public class WechatGetUserInfoUtil {
public static final String APPID = "wxd5fc6c544e752529";
public static final String SECRET = "c2bf267226c0157c859da6934ee3c298";
public static Map<String, String> getWxLoginInfo(String code) {
String apiUrl = "https://api.weixin.qq.com/sns/jscode2session?appid=" + APPID + "&secret=" + SECRET + "&js_code=" + code + "&grant_type=authorization_code";
String responseBody = HttpUtil.get(apiUrl);
Map jsonObject = new Gson().fromJson(responseBody, Map.class);
Map<String, String> map = new HashMap<>();
map.put("openid", jsonObject.get("openid").toString());
map.put("session_key", jsonObject.get("session_key").toString());
return map;
}
/**
* 解密用户手机号
*
* @param encryptedData 包括敏感数据在内的完整用户信息的加密数据
* @param iv 加密算法的初始向量
*/
public static String getMobile(String encryptedData, String sesskey, String iv) {
String result = decryptData(encryptedData, sesskey, iv);
if (result == null) {
return null;
}
Map<String, String> map = new JSONObject(result).toBean(Map.class);
return map.get("phoneNumber");
}
public static String decryptData(String encryptedData, String sessionKey, String iv) {
// 被加密的数据
byte[] dataByte = Base64Utils.decode(encryptedData.getBytes());
// 加密秘钥
byte[] keyByte = Base64Utils.decode(sessionKey.getBytes());
// 偏移量
byte[] ivByte = Base64Utils.decode(iv.getBytes());
try {
// 如果密钥不足16位,那么就补足. 这个if 中的内容很重要
int base = 16;
if (keyByte.length % base != 0) {
int groups = keyByte.length / base + (keyByte.length % base != 0 ? 1 : 0);
byte[] temp = new byte[groups * base];
Arrays.fill(temp, (byte) 0);
System.arraycopy(keyByte, 0, temp, 0, keyByte.length);
keyByte = temp;
}
// 初始化
Security.addProvider(new BouncyCastleProvider());
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding", "BC");
SecretKeySpec spec = new SecretKeySpec(keyByte, "AES");
AlgorithmParameters parameters = AlgorithmParameters.getInstance("AES");
parameters.init(new IvParameterSpec(ivByte));
// 初始化
cipher.init(Cipher.DECRYPT_MODE, spec, parameters);
byte[] resultByte = cipher.doFinal(dataByte);
if (null != resultByte && resultByte.length > 0) {
String result = new String(resultByte, "UTF-8");
return result;
}
} catch (NoSuchAlgorithmException e) {
log.error(e.getMessage(), e);
} catch (NoSuchPaddingException e) {
log.error(e.getMessage(), e);
} catch (InvalidParameterSpecException e) {
log.error(e.getMessage(), e);
} catch (IllegalBlockSizeException e) {
log.error(e.getMessage(), e);
} catch (BadPaddingException e) {
log.error(e.getMessage(), e);
} catch (UnsupportedEncodingException e) {
log.error(e.getMessage(), e);
} catch (InvalidKeyException e) {
log.error(e.getMessage(), e);
} catch (InvalidAlgorithmParameterException e) {
log.error(e.getMessage(), e);
} catch (NoSuchProviderException e) {
log.error(e.getMessage(), e);
}
return null;
}
}
实现时需要先调用:getWxLoginInfo得到openid和session_key信息,然后调用获取手机号getMobile得到手机号,最后通过openid取获取用户信息,如果不存在,则创建一个用户,并设置openid和手机号信息,最后返回token即可。
3、修改用户昵称头像信息
前端:
<button class="authorization" type="default" open-type="chooseAvatar" @chooseavatar="chooseavatar" >上传微信头像</button>
<input id="nickname-input" v-model="nickname" v- class="authorization white" type="nickname" placeholder="请输入用户昵称" >
chooseavatar(e) {
this.avater = this.avater;//如果需要上传头像,则先上传再赋值
},
此处不是很完善,后面完善
4、获取定位信息
前端:
uni.getLocation({
type: 'gcj02',
success: function(res) {
///处理业务
res.latitude
res.longitude
},
fail: function(err) {
console.log("授权失败");
}
});
需要打开manifest.json进行配置请求定位权限
注意:微信开发者工具中,不支持定位,也不会弹出授权申请,只有在手机上才可以,所以微信开发者工具上时,可以采用设置默认值进行测试。文章来源:https://www.toymoban.com/news/detail-590906.html
如果需要持续定位,则需要单独申请后台定位授权,具体前往uniapp查看。文章来源地址https://www.toymoban.com/news/detail-590906.html
到了这里,关于基于uniapp+java实现微信小程序无感登录,授权手机号登录,获取昵称头像,获取定位信息的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!