当前位置:   article > 正文

微信小程序获取手机号授权完整实现_微信授权手机号

微信授权手机号

官方文档:https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/login.html
在这里插入图片描述

一.app.js配置

App({
  onLaunch: function () {
    
  },
  onShow: function () {
    
  },
  onHide: function () {
    //	console.log(getCurrentPages())
  },
  onError: function (msg) {
    //console.log(msg)
  },

  globalData: {
    userInfo: null,
    appid: "",
    appsecret: "",
    phoneNumber: '',
    getSessionKeyUrl: 'http://localhost:8888/test/getsessionkey',
    getPhoneUrl: 'http://localhost:8888/test/getphone',
    orderHomeUrl: 'http://localhost:8888/login?phone=',
    driverLoginUrl: 'http://localhost:8888/driver/login'
  }
});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

二.app.json配置

{
  "pages": [
    "pages/login/login",
    "pages/main/main",
    "pages/driverlogin/driverlogin"
  ],
  "window": {
    "backgroundTextStyle": "light",
    "navigationBarBackgroundColor": "#F8F8F8",
    "navigationBarTitleText": "小程序",
    "navigationBarTextStyle": "black"
  },
  "sitemapLocation": "sitemap.json"
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

三.微信授权

1.页面
<view wx:if="{{isShow}}" >
    <view class="container" style="padding:0rpx">
        <image src='./login.png' style="z-index:-99;width:100%;height:100%;" mode="widthFix"></image>
        <view style="margin-top:10rpx; width: 98%;" >
            <button class="show" type="primary" lang="zh_CN" open-type='getPhoneNumber'  bindgetphonenumber="getPhoneNumber">{{wechat}}</button>
        </view>
    </view>
</view> 
<view class="container" wx:else></view>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
2.页面样式
.show{
  display: block;
  border-radius: 8rpx;
  margin: 20rpx 20rpx 20rpx 20rpx;
  font-size: 35rpx;
}

.container{
  position: fixed;  /*关键属性,设置为fixed*/
  display: flex;
  flex-direction: column;
  width: 100%;
  height: 100%;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
3.json
{
  "usingComponents": {}
}
  • 1
  • 2
  • 3
4.js
const app = getApp();
Page({
  data: {
    // 判断小程序的API,回调,参数,组件等是否在当前版本可用。
    canIUse: wx.canIUse('button.open-type.getPhoneNumber'),
    wechat: '微信快捷登录',
    isShow: false
  },
  onLoad: function() {
    // 从缓存中取手机号
    console.log("获取手机号!")
    try {
      var value = wx.getStorageSync('phoneNumber')
      if (value) { // 说明已登录 跳转 页面
        console.log("获取缓存:"+value)
        wx.navigateTo({
          url: '../main?param=' + value
        })
      }else{// 未登录 显示 微信授权页面
        this.setData({
          isShow: true
        })
      }
    } catch (e) {

    }
    // 解决第一次获取手机号失败问题
    wx.login({
      success: res => {
        if(res.code){
          console.log("code->", res.code)
        }
      }
    })
  },
  // 0.获取手机号授权
  getPhoneNumber: function(e) {
    // 用户拒绝授权
    if(e.detail.errMsg == "getPhoneNumber:fail user deny") {
      wx.showToast({
        icon: "none",
        title: '请允许获取手机号,否则功能不可用!',
      })
      return
    }
   
    /// 用户允许授权
    console.log("iv->", e.detail.iv); //包括敏感数据在内的完整用户信息的加密数据,需要解密
    console.log("encryptedData->", e.detail.encryptedData); //加密算法的初始向量,解密需要用到

    /// 获取手机号
    // 1.获取临时登录凭证code
    wx.login({
      success: res => {
        if(res.code){
          this.code = res.code;
          console.log("code->", res.code)
          this.getSessionKey(res.code, e.detail.encryptedData, e.detail.iv);
        }
      }
    })
    },
  // 2.访问登录凭证校验接口获取session_key(后续改成后台实现)
  getSessionKey: function(js_code, encryptedData, iv) {
    wx.request({
      url: app.globalData.getSessionKeyUrl,
      data: {
          'jscode': js_code,
          'sign': 'sign'
      },
      method: 'GET', 
      header: {
          'content-type': 'application/json'
      }, // 设置请求的 header
      success: function(data) {
        console.log("session_key->", data.data)
        if(data.data==undefined){
          wx.showToast({
            icon: "none",
            title: 'session_key获取失败,请重新登录!',
          })
          return
        }
        // 3. 解密获取手机号
        wx.request({
          url: app.globalData.getPhoneUrl,
          data: {
              'encryptedData': encodeURIComponent(encryptedData),//需要进行编码
              'iv': iv,
              'sessionKey': data.data,
              'sign': 'sign',
          },
          method: 'GET', 
          header: {
              'content-type': 'application/json'
          }, // 设置请求的 header
          success: function(data2) {
              console.log(data2.data.phoneNumber)
              if(data2.statusCode == 200) { 
                if(data2.data.phoneNumber==undefined){
                  // 获取手机号失败 跳转到 常规 用户登录页面(通过webview)
                  wx.navigateTo({
                    url: '../driverlogin/driverlogin'
                  })
                  return
                }
                // 存储数据到缓存
                wx.setStorage({
                  key:"phoneNumber",
                  data:data2.data.phoneNumber
                })
                // 4.跳转web-view页面
                wx.navigateTo({
                  url: '../main?param=' + data2.data.phoneNumber
                }) // 4
              }
          },
          fail: function(err) {
              console.log(err);
              wx.showToast({
                icon: "none",
                title: '获获取手机号失败,请重试!',
              })
          }
        })// 3
      },
      fail: function(err) {
          console.log(err);
          wx.showToast({
            icon: "none",
            title: 'session_key获取失败,请重新登录!',
          })
          return
      }
    })
  }// 2
})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
4.后端实现
1)获取sessionkey
@GetMapping("getsessionkey")
@ResponseBody
public synchronized Object getSessionKey(String jscode,String sign) {
	MyResult res = new MyResult();
	if(StringUtils.isBlank(jscode)) {
		res.setCode(-1);
		res.setMsg("鉴权失败!");
		return res;
	}
	
	if(!checkcode.equals("sign")) {
		res.setCode(-1);
		res.setMsg("鉴权失败!");
		return res;
	}
	
	if(StringUtils.isBlank(sign)||checkcode.equals("undefined")) {
		res.setCode(-1);
		res.setMsg("无效参数!");
		return res;
	}
	
	OkHttpClient client = new OkHttpClient().newBuilder()
			  .build();
	String requestStr = miniProgramConfig.getSessionkeyurl()
			  +"?appid="+miniProgramConfig.getAppid()
			+"&secret="+miniProgramConfig.getSecret()
			  +"&js_code="+jscode
			  +"&grant_type=authorization_code";
	Request request = new Request.Builder()
	  .url(requestStr)
	  .method("GET", null)
	  .build();
	try {
		Response response = client.newCall(request).execute();
		String responseStr = response.body().string();
		JSONObject jsonObject = JSONObject.parseObject(responseStr);
		// 获取到session_key
		String session_key = jsonObject.getString("session_key");
		
		if(StringUtils.isBlank(session_key)) {
			res.setCode(-1);
			res.setMsg("获取sessionkey失败!");
			return res;
		}
		return session_key;
	} catch (IOException e) {
		logger.error("encryptedData,decode失败!", e);
		res.setCode(-1);
		res.setMsg("获取sessionkey失败!");
		return res;
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
2)获取解密手机号
@GetMapping("getphone")
	@ResponseBody
	public synchronized Object getPhone(String encryptedData, String iv, String sessionKey,String sign) {
		MyResult res = new MyResult();
		if(StringUtils.isBlank(sign)) {
			res.setCode(-1);
			res.setMsg("鉴权失败!");
			return res;
		}
		
		if(!sign.equals("sign")) {
			res.setCode(-1);
			res.setMsg("鉴权失败!");
			return res;
		}
		
		if(StringUtils.isBlank(encryptedData)
				||encryptedData.equals("undefined")
				||StringUtils.isBlank(iv)
				||iv.equals("undefined")
				||StringUtils.isBlank(sessionKey)
				||sessionKey.equals("undefined")) {
			res.setCode(-1);
			res.setMsg("参数错误!");
			return res;
		}
		
		// 解码
		try {
			encryptedData = URLDecoder.decode(encryptedData,"UTF-8");
		} catch (UnsupportedEncodingException e) {
			res.setCode(-1);
			res.setMsg("encryptedData,decode失败!");
			logger.error("encryptedData,decode失败!", e);
			return res;
		}
		return WechatDecryptDataUtil.decryptData(encryptedData, sessionKey, iv);
		
	}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
3)解密工具类
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.encoders.Base64;

import com.zit.tis.wechat.miniproject.MiniProgramController;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.Key;
import java.security.Security;

/**
 * 微信工具类
 */
public class WechatDecryptDataUtil {
	private static Logger logger = LogManager.getLogger(WechatDecryptDataUtil.class);

    public static void main(String[] args) {
        String result = decryptData(
                "111==",
                "222==",
                "333=="
        );
        System.out.println("result = " + result);
    }

    public synchronized static String decryptData(String encryptDataB64, String sessionKeyB64, String ivB64) {
    	String res = null;
    	try {
    		res = new String(
                    decryptOfDiyIV(
                            Base64.decode(encryptDataB64),
                            Base64.decode(sessionKeyB64),
                            Base64.decode(ivB64)
                    )
            );
		} catch (Exception e) {
			logger.error("encryptDataB64:"+encryptDataB64+"\n"+"sessionKeyB64:"+sessionKeyB64+"\n"+"ivB64:"+ivB64);
		}
        
        return res;
    }

    private static final String KEY_ALGORITHM = "AES";
    private static final String ALGORITHM_STR = "AES/CBC/PKCS7Padding";
    private static Key key;
    private static Cipher cipher;

    private static void init(byte[] keyBytes) {
        // 如果密钥不足16位,那么就补足.  这个if 中的内容很重要
        int base = 16;
        if (keyBytes.length % base != 0) {
            int groups = keyBytes.length / base + (keyBytes.length % base != 0 ? 1 : 0);
            byte[] temp = new byte[groups * base];
            Arrays.fill(temp, (byte) 0);
            System.arraycopy(keyBytes, 0, temp, 0, keyBytes.length);
            keyBytes = temp;
        }
        // 初始化
        Security.addProvider(new BouncyCastleProvider());
        // 转化成JAVA的密钥格式
        key = new SecretKeySpec(keyBytes, KEY_ALGORITHM);
        try {
            // 初始化cipher
            cipher = Cipher.getInstance(ALGORITHM_STR, "BC");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 解密方法
     *
     * @param encryptedData 要解密的字符串
     * @param keyBytes      解密密钥
     * @param ivs           自定义对称解密算法初始向量 iv
     * @return 解密后的字节数组
     */
    private static byte[] decryptOfDiyIV(byte[] encryptedData, byte[] keyBytes, byte[] ivs) {
        byte[] encryptedText = null;
        init(keyBytes);
        try {
            cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(ivs));
            encryptedText = cipher.doFinal(encryptedData);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return encryptedText;
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/284651
推荐阅读
相关标签
  

闽ICP备14008679号