爱收集资源网

解锁微信用户绑定手机号的小程序功能

网络整理 2023-10-28 01:03

在小程序开发中,获取陌陌用户绑定的手机号功能,详尽可查看官方文档:陌陌官方文档·小程序获取手机号

获取陌陌用户绑定的手机号,需先调用wx.login插口。

由于须要用户主动触发能够发起获取手机号插口,所以该功能不由API来调用,需用button组件的点击来触发。

注意:目前该插口针对非个人开发者,且完成了认证的小程序开放(不包含海外主体)。需慎重使用,若用户举报较多或被发觉在何必要场景下使用,陌陌有权永久回收该小程序的该插口权限。

后端

须要将button组件open-type的值设置为getPhoneNumber,当用户点击并同意以后,可以通过bindgetphonenumber风波反弹获取到陌陌服务器返回的加密数据,之后在第三方服务端结合session_key以及app_id进行揭秘获取手机号。

<button open-type="getPhoneNumber" @getphonenumber="getPhoneNumber">获取手机号
methods: {
	getPhoneNumber(e){
		if(e.detail.errMsg == "getPhoneNumber:ok"){
			console.log('用户同意提供手机号');
			console.log(JSON.stringify(e.detail.encryptedData));
			console.log(JSON.stringify(e.detail.iv));
			var encryptedData = e.detail.encryptedData;
			var iv = e.detail.iv;
		}
	}
},

注意:

在反弹中调用wx.login登陆,可能会刷新登陆态。此时服务器使用code换取的sessionKey不是加密时使用的sessionKey,致使揭秘失败。建议开发者提早进行login;或则在反弹中先使用checkSession进行登陆态检测,防止login刷新登陆态。

以上基本都是官网内容,接出来俺们剖析一下获取流程。

后端wx.login()用户授权->获取登陆用户code值->发送给前端前端按照code和小程序的appId和appSecret调用陌陌官方插口获取用户的session_key和openId陌陌官方文档·小程序服务端code2Session后端通过button调用陌陌的获取手机号功能陌陌按照当前用户的session_key(也就是刚才前端通过code获取的code值)和用户手机号等敏感数据进行签名/加密陌陌将数据+签名+密文串发送给小程序,由于没有发送session_key,因而难以伪造签名,难以揭秘后端小程序将数据+签名+密文串发给前端,前端进行揭秘得到想要的数据。

陌陌官方文档·小程序揭秘

其中有疑惑的点是,第2步、第6步中,前端用到的session_key。sessionKey是用户的标示,也就是说每位用户同一时间点击步入的时侯是不一致的。并且每位用户在wx.login以后,也是会刷新sessionKey的。

据此,我的看法是:由于sessionKey是按照code换来的,每次调用wx.login以后,code也会跟sessionKey一起变。也就是说code跟sessionKey可以觉得是同一个东西,起码同一个作用。

所以,前端在第2步依照code获取sessionKey的时侯,将code和sessionKey存到了缓存中。也让后端将用户的code标示存在顾客端缓存中。

第5步调用的时侯也将缓存中的code传递给前端,前端通过当前code去缓存里取出sessionKey来揭秘。

推论:后端wx.login()用户授权->获取登陆用户code值->发送给前端并将code缓存一份前端按照code和小程序的appId和appSecret调用陌陌官方插口获取用户的session_key和openId,并将code为key,session_key为value缓存一份后端通过button调用陌陌的获取手机号功能陌陌按照当前用户的session_key(也就是刚才前端通过code获取的code值)和用户手机号等敏感数据进行签名/加密陌陌将数据+签名+密文串发送给小程序,由于没有发送session_key,因而难以伪造签名,难以揭秘后端小程序将数据+签名+密文串+缓存中的code发给前端,前端按照code去缓存中获得session_key进行揭秘得到想要的数据。细节:缓存中的值我设置的3天的过期时间

陌陌开放社区小程序登入session_key的有效期问题2018年

注意:这儿虽然是陌陌开放社区,并且也是2018年的回复,所以是否为3天这儿不做证明与验证,至于过期时间需依照公司实际业务需求确定:如有用户量较大,服务器显存不足,redis占用过大等问题。可适当调整,由于每位用户退出小程序后,过段时间在步入时,可能须要再度授权获取code值,所以也会造成之前的code失效,redis存入过期数据。并且陌陌官方仍然指出,不提供session_key的过期时间,陌陌不会把session_key的有效期告知开发者。我们会依据用户使用小程序的行为对session_key进行续期。用户越频繁使用小程序,session_key有效期越长。

后端获取手机号时取code值的逻辑:

假如缓存中有code值

假如缓存中没有code值

注意:

签名校准以及数据加揭秘涉及用户的会话秘钥session_key。开发者应当事先通过wx.login登陆流程获取会话秘钥session_key并保存在服务器。为了数据不被篡改微信小程序code无效,开发者不应当把session_key传到小程序顾客端等服务器外的环境。

会话秘钥session_key有效性

开发者若果遇见由于session_key不正确而校准签名失败或揭秘失败,请关注下边几个与session_key有关的注意事项。

wx.login调用时,用户的session_key可能会被更新而导致旧session_key失效(刷新机制存在最短周期,假如同一个用户短时间内多次调用wx.login,并非每次调用都造成session_key刷新)。开发者应当在明晰须要重新登陆时才调用wx.login,及时通过auth.code2Session插口更新服务器储存的session_key。陌陌不会把session_key的有效期告知开发者。我们会依据用户使用小程序的行为对session_key进行续期。用户越频繁使用小程序,session_key有效期越长。开发者在session_key失效时微信小程序code无效,可以通过重新执行登陆流程获取有效的session_key。使用插口wx.checkSession可以校准session_key是否有效,因而防止小程序反复执行登陆流程。当开发者在实现自定义登陆态时,可以考虑以session_key有效期作为自身登陆态有效期,也可以实现自定义的时效性策略。附:揭秘代码

须要提早导出的maven依赖

<dependency>
    <groupId>org.bouncycastlegroupId>
    <artifactId>bcprov-jdk16artifactId>
    <version>1.46version>
dependency>

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang.StringUtils;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import javax.validation.constraints.NotNull;
import java.security.Security;
import java.security.spec.AlgorithmParameterSpec;
@Slf4j
public class AESUtils {
    // 加密模式
    private static final String ALGORITHM = "AES/CBC/PKCS7Padding";
    private static final String CHARSET_NAME = "UTF-8";
    private static final String AES_NAME = "AES";
    //解决java.security.NoSuchAlgorithmException: Cannot find any provider supporting AES/CBC/PKCS7Padding
    static {
        Security.addProvider(new BouncyCastleProvider());
    }
    /**
     * 解密
     *
     * @param content 目标密文
     * @param key     秘钥
     * @param iv      偏移量
     * @return
     */
    public static String decrypt(@NotNull String content, @NotNull String key, @NotNull String iv) {
        try {
            Cipher cipher = Cipher.getInstance(ALGORITHM);
            byte[] sessionKey = java.util.Base64.getDecoder().decode(key);
            SecretKeySpec keySpec = new SecretKeySpec(sessionKey, AES_NAME);
            byte[] ivByte = java.util.Base64.getDecoder().decode(iv);
            AlgorithmParameterSpec paramSpec = new IvParameterSpec(ivByte);
            cipher.init(Cipher.DECRYPT_MODE, keySpec, paramSpec);
            return new String(cipher.doFinal(Base64.decodeBase64(content)), CHARSET_NAME);
        } catch (Exception e) {
            log.error("解密失败:{}", e);
            e.printStackTrace();
        }
        return StringUtils.EMPTY;
    }
    
}

测试:

    public static void main(String[] args) {
        String sessionKey = "zF6lhhRqTdWJ8sb45RTxsw==";
        String encryptedData = "JXZ5dxBn7EqgRWTbqt50rxrN69Y9okDdL0YzvrSwNjKA9blYJagZbhovcwbhFy8vVaqjVVEjIl451JOCXIB2fpNpq0sbIxV+B28pKWLA8y2jn7R1iTE7O7k/tW1yVDMZwqRQyTw9lV/qlISw+HX887DeVWCfem6lx8jZ/C+kshJdig4Li06AIA9A9smToZYI";
        String iv = "CO5eq/F5TTv9SuwiMLDNaA==";
        String decrypt = AESUtils.decrypt(encryptedData, sessionKey, iv);
        System.out.println(decrypt);
    }

将json转成map:

Gson gson = new Gson();
Map<String,Object> stringList = gson.fromJson(decrypt, new TypeToken<Map<String,Object>>() {}.getType());
stringList.forEach((k,v)-> System.out.println(k+":"+v));

gson需注意时间戳处理

或则

ObjectMapper objectMapper = new ObjectMapper();
Map<String, Object> userMap = objectMapper.readValue(decrypt, Map.class);
userMap.forEach((k,v)-> System.out.println(k+":"+v));

微信小程序code无效
上一篇:联想E550笔记本开机异常,如何打开BIOS? 下一篇:没有了
相关文章