基于uniapp+java实现微信小程序无感登录,授权手机号登录,获取昵称头像,获取定位信息

项目背景

使用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进行配置请求定位权限
在这里插入图片描述

注意:微信开发者工具中,不支持定位,也不会弹出授权申请,只有在手机上才可以,所以微信开发者工具上时,可以采用设置默认值进行测试。

如果需要持续定位,则需要单独申请后台定位授权,具体前往uniapp查看。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值