微信扫码拉起小程序手机号授权跨端登录

开发小程序手机号授权需要到微信公众平台

        1.获取微信开发 secret,在 设置 - 开发设置 页中获得

        2.进行 微信认证

        3.后端服务需要申请https域名

        4.开发测试时,需要打开微信开发者工具-详情(右上角)-项目配置-域名信息 配置request合法域名

微信小程序代码段

wxml: 背景图片需要自己替换

<!--index.wxml-->
<view class="container">
  <image class="image-bg" src="../../assest/img/bg.png"></image>
  <image class="image-uav" src="../../assest/img/uav.png"></image>

  <view class="title">
    <text class="title-content">{{title}}</text>
  </view>

  <button wx:if="{{!exitFlag && checked}}" class="image-btn" open-type="getPhoneNumber" bindgetphonenumber="getPhoneNumber" style="width: 80%;"> {{btn}} </button>
  <button wx:if="{{!exitFlag && !checked}}" class="image-btn" bindtap="getPhoneNumber" style="width: 80%;"> {{btn}} </button>
  <view wx:if="{{!exitFlag}}" class="agreement">
    <view>
      <checkbox-group class="agreement-checkbox-group" bindchange="checkboxChange">
        <checkbox value="agreementVal" checked="{{checked}}">
        </checkbox>
      </checkbox-group>
      <text class="agreement-content" bindtap="showModel">{{agreement}}</text>
    </view>
  </view>
  <navigator wx:if="{{exitFlag}}" class="exit-btn" open-type="exit" target="miniProgram" style="width: 80%;"> {{exitBtn}} </navigator>



  <!-- 用户协议 -->
  <view class="model_box" hidden="{{hide}}">
    <view class="mb-tit">
      用户服务协议
      <icon class="mb-cancel" type="cancel" size="23" bindtap="showModel"></icon>
    </view>
    <view class="mb-content">
      <view class="mb-con">引言</view>
      <view class="mb-con">通用xxx:</view>
    </view>
  </view>
</view>

ts:

const app = getApp<IAppOption>()
Page({
  data: {
    title: '你好,\n欢迎使用xx授权登录',
    agreement: '我已阅读并同意 xx网络平台用户协议\n及领克个人信息保护政策',
    btn: '微信授权获取个人信息',
    exitBtn: '点击退出小程序',
    exitFlag: false,
    userInfo: {},
    hasUserInfo: false,
    //开发环境
    // getPhoneNumberUrl: 'http://localhost:8081/wx/api/getPhoneNumber',
    //测试环境
    getPhoneNumberUrl: 'https://xxx-dev/wx/api/getPhoneNumber',
    //生产环境
    // getPhoneNumberUrl: 'https://xxx-prod/wx/api/getPhoneNumber',
    checked: false,
    hide: true,
    cb: 0,
    uid: undefined,
  },
  onLoad() {
    const pages: any = getCurrentPages();
    const currentPage: any = pages[pages.length - 1];
    if (currentPage.options.uid) {
      this.setData({
        uid: currentPage.options.uid
      })
    }
  },
  checkboxChange(e: any) {
    let val = e.detail.value
    if (val.length > 0) {
      this.setData({
        checked: true,
      })
    } else {
      this.setData({
        checked: false,
      })
    }
  },
  showModel() {
    if (this.data.hide) {
      this.setData({
        checked: true
      })
    }
    this.setData({
      hide: !this.data.hide
    })
  },
  getPhoneNumber(e: any) {
    if (!this.data.checked) {
      wx.showToast({
        title: '请阅读并同意',
        icon: 'error',
        duration: 800
      })
      return;
    }
    let detail = e.detail;
    if (detail.errMsg === "getPhoneNumber:ok") {
      // 动态令牌
      let code = detail.code;
      let that = this;
      wx.request({
        url: this.data.getPhoneNumberUrl,
        method: 'POST',
        header: {
          'content-type': 'application/json' // 默认值
        },
        data: {
          code: code,
          uid: this.data.uid
        },
        success() {
          wx.showToast({
            title: '授权成功',
            icon: 'success',
            duration: 1000,
            complete: function () {
              that.setData({
                exitFlag: true
              })
            }
          })
        },
        fail() {
          wx.showToast({
            title: '授权失败',
            icon: 'error',
            duration: 1000
          })
        },
      })
    }
  },
})

wxss:

/**index.wxss**/

.image-bg {
  position: absolute;
  left: 0;
  bottom: 0;
  width: 100%;
  height: 100%;
  z-index: -999;
}

.image-uav {
  position: absolute;
  top: 410rpx;
  width: 55%;
  height: 13%;
}

.title {
  position: absolute;
  top: 680rpx;
}

.title-content {
  color: aliceblue;
  font-size: 50rpx;
  letter-spacing: 5rpx;
}

.image-btn {
  position: absolute;
  bottom: 200rpx;
  background-color: #339586;
  color: aliceblue;
}

checkbox .wx-checkbox-input {
  border-radius: 50%;
  border: 2rpx solid #5e5e5f;
  height: 24rpx;
  width: 24rpx;
  margin-top: -33rpx;
}

checkbox .wx-checkbox-input.wx-checkbox-input-checked:before {
  font-size: 25rpx;
  font-weight: bold;
}

.agreement {
  position: absolute;
  bottom: 100rpx;
  justify-content: center;
  align-content: center;
  text-align: center;
}

.agreement-checkbox-group{
  position: absolute;
  bottom: 23rpx;
  left: -33rpx;
}

.agreement-content {
  color: aliceblue;
  font-size: 20rpx;
  letter-spacing: 2rpx;
}

.exit-btn {
  position: absolute;
  bottom: 200rpx;
  height: 70rpx;
  text-align: center;
  background-color: #339586;
  color: aliceblue;
  border-radius: 10rpx;
  line-height: 65rpx;
  font-weight: bold;
}

.model_box {
  position: fixed;
  top: 50%;
  left: 50%;
  height: 75%;
  width: 85%;
  transform: translate(-50%, -50%);
  z-index: 1000;
  background: #fff;
  opacity: 0.9;
  border-radius: 15rpx;
}

.mb-content {
  padding: 10rpx 20rpx 10rpx 25rpx;
  box-sizing: border-box;
  height: 91%;
  overflow: scroll;
}

.mb-tit {
  padding: 15rpx 0rpx;
  box-sizing: border-box;
  font-size: 34rpx;
  text-align: center;
}

.mb-cancel {
  position: fixed;
  right: 5%;
}

.wx-icon-cancel {
  color: #5e5e5f;
}

.mb-con {
  font-size: 22rpx;
  text-indent: 2rem;
  line-height: 1.5;
}

后端java:

@Service
public class WxApiServiceImpl implements WxApiService {
    private static final Logger log = LoggerFactory.getLogger(WxApiServiceImpl.class);
    @Autowired
    private RedisCache redisCache;
    @Value("${wx.appid}")
    public String appid;
    @Value("${wx.secret}")
    public String secret;
    @Value("${wx.grantType}")
    public String grantType;
    @Value("${wx.getPhoneNumber}")
    public String getPhoneNumber;
    @Value("${wx.getQRCode}")
    public String getQRCode;
    @Value("${wx.getAccessToken}")
    public String getAccessToken;
    @Value("${wx.numberTimeOut}")
    public int numberTimeOut;

    @Override
    public JSONObject getQRCode(WxInfo wxInfo) {
        try {
            //获取token
            String getAccessTokenParams = "grant_type=" + grantType + "&appid=" + appid +
                    "&secret=" + secret;
            String accessTokenJsonStr = HttpUtils.sendPost(getAccessToken, getAccessTokenParams);
            JSONObject accessTokenJson = JSONObject.parseObject(accessTokenJsonStr);
            //获取小程序二维码
            String params = "access_token=" + accessTokenJson.getString("access_token");
            JSONObject codeBodyParams = new JSONObject();
            codeBodyParams.put("path", "pages/index/index?uid=" + wxInfo.getUid());
            codeBodyParams.put("width", "430");
            String code = HttpUtils.sendPostWXCode(getQRCode, params, codeBodyParams);
            JSONObject data = new JSONObject();
            data.put("code", code);
            return new ResponseUtil.Builder(AppConstants.SUCCESS, AppConstants.SUCCESS_MSG).data(data).build();
        } catch (Exception e) {
            log.warn(">>>>>>>>>>>>>>>>微信API调用失败!<<<<<<<<<<<<<<<<<<<", e);
            return new ResponseUtil.Builder(AppConstants.WX_API_ERROR, AppConstants.WX_API_ERROR_MSG).build();
        }
    }

    @Override
    public JSONObject getPhoneNumber(WxInfo wxInfo) {
        try {
            //获取token
            String getAccessTokenParams = "grant_type=" + grantType + "&appid=" + appid +
                    "&secret=" + secret;
            String accessTokenJsonStr = HttpUtils.sendPost(getAccessToken, getAccessTokenParams);
            JSONObject accessTokenJson = JSONObject.parseObject(accessTokenJsonStr);
            String params = "access_token=" + accessTokenJson.getString("access_token");
            JSONObject bodyParams = new JSONObject();
            bodyParams.put("code", wxInfo.getCode());
            //获取手机号
            String phoneNumberJsonStr = HttpUtils.sendPostUrlParams(getPhoneNumber, params, bodyParams);
            JSONObject phoneNumberJson = JSONObject.parseObject(phoneNumberJsonStr);
            phoneNumberJson.put("uid", wxInfo.getUid());
            //缓存手机号
            redisCache.setCacheObject(Constants.QR_DATA_KEY + wxInfo.getUid(), phoneNumberJson, numberTimeOut, TimeUnit.MINUTES);

            return new ResponseUtil.Builder(AppConstants.SUCCESS, AppConstants.SUCCESS_MSG).data(phoneNumberJson).build();
        } catch (Exception e) {
            log.warn(">>>>>>>>>>>>>>>>微信API调用失败!<<<<<<<<<<<<<<<<<<<", e);
            return new ResponseUtil.Builder(AppConstants.WX_API_ERROR, AppConstants.WX_API_ERROR_MSG).build();
        }
    }

    @Override
    public JSONObject getPhoneNumberByUid(WxInfo wxInfo) {
        JSONObject redisCode = redisCache.getCacheObject(Constants.QR_DATA_KEY + wxInfo.getUid());
        if (redisCode == null) {
            return new ResponseUtil.Builder(AppConstants.WX_QR_DATA_ERROR, AppConstants.WX_QR_DATA_ERROR_MSG).build();
        }
        return new ResponseUtil.Builder(AppConstants.SUCCESS, AppConstants.SUCCESS_MSG).data(redisCode).build();
    }

    @Override
    public JSONObject clearQRData(WxInfo wxInfo) {
        if (StringUtils.isNotEmpty(wxInfo.getUid())) {
            log.info(">>>>>>>>>>>>>>>>clear redis qr data ," + Constants.QR_DATA_KEY + wxInfo.getUid() + "<<<<<<<<<<<<<<<<<<<");
            redisCache.deleteObject(Constants.QR_DATA_KEY + wxInfo.getUid());
        }
        return new ResponseUtil.Builder(AppConstants.SUCCESS, AppConstants.SUCCESS_MSG).build();
    }
}

http工具类:

public class HttpUtils {
    private static final Logger log = LoggerFactory.getLogger(HttpUtils.class);

    /**
     * 向指定 URL 发送GET方法的请求
     *
     * @param url   发送请求的 URL
     * @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
     * @return 所代表远程资源的响应结果
     */
    public static String sendGet(String url, String param) {
        return sendGet(url, param, Constants.UTF8);
    }

    /**
     * 向指定 URL 发送GET方法的请求
     *
     * @param url         发送请求的 URL
     * @param param       请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
     * @param contentType 编码类型
     * @return 所代表远程资源的响应结果
     */
    public static String sendGet(String url, String param, String contentType) {
        StringBuilder result = new StringBuilder();
        BufferedReader in = null;
        try {
            String urlNameString = url + "?" + param;
            log.info("sendGet - {}", urlNameString);
            URL realUrl = new URL(urlNameString);
            URLConnection connection = realUrl.openConnection();
            connection.setRequestProperty("accept", "*/*");
            connection.setRequestProperty("connection", "Keep-Alive");
            connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
            connection.connect();
            in = new BufferedReader(new InputStreamReader(connection.getInputStream(), contentType));
            String line;
            while ((line = in.readLine()) != null) {
                result.append(line);
            }
            log.info("recv - {}", result);
        } catch (ConnectException e) {
            log.error("调用HttpUtils.sendGet ConnectException, url=" + url + ",param=" + param, e);
        } catch (SocketTimeoutException e) {
            log.error("调用HttpUtils.sendGet SocketTimeoutException, url=" + url + ",param=" + param, e);
        } catch (IOException e) {
            log.error("调用HttpUtils.sendGet IOException, url=" + url + ",param=" + param, e);
        } catch (Exception e) {
            log.error("调用HttpsUtil.sendGet Exception, url=" + url + ",param=" + param, e);
        } finally {
            try {
                if (in != null) {
                    in.close();
                }
            } catch (Exception ex) {
                log.error("调用in.close Exception, url=" + url + ",param=" + param, ex);
            }
        }
        return result.toString();
    }

    /**
     * 向指定 URL 发送POST方法的请求
     *
     * @param url   发送请求的 URL
     * @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
     * @return 所代表远程资源的响应结果
     */
    public static String sendPost(String url, String param) {
        PrintWriter out = null;
        BufferedReader in = null;
        StringBuilder result = new StringBuilder();
        try {
            String urlNameString = url;
            log.info("sendPost - {}", urlNameString);
            URL realUrl = new URL(urlNameString);
            URLConnection conn = realUrl.openConnection();
            conn.setRequestProperty("accept", "*/*");
            conn.setRequestProperty("connection", "Keep-Alive");
            conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
            conn.setRequestProperty("Accept-Charset", "utf-8");
            conn.setRequestProperty("contentType", "utf-8");
            conn.setDoOutput(true);
            conn.setDoInput(true);
            out = new PrintWriter(conn.getOutputStream());
            out.print(param);
            out.flush();
            in = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"));
            String line;
            while ((line = in.readLine()) != null) {
                result.append(line);
            }
            log.info("recv - {}", result);
        } catch (ConnectException e) {
            log.error("调用HttpUtils.sendPost ConnectException, url=" + url + ",param=" + param, e);
        } catch (SocketTimeoutException e) {
            log.error("调用HttpUtils.sendPost SocketTimeoutException, url=" + url + ",param=" + param, e);
        } catch (IOException e) {
            log.error("调用HttpUtils.sendPost IOException, url=" + url + ",param=" + param, e);
        } catch (Exception e) {
            log.error("调用HttpsUtil.sendPost Exception, url=" + url + ",param=" + param, e);
        } finally {
            try {
                if (out != null) {
                    out.close();
                }
                if (in != null) {
                    in.close();
                }
            } catch (IOException ex) {
                log.error("调用in.close Exception, url=" + url + ",param=" + param, ex);
            }
        }
        return result.toString();
    }

    public static String sendPostUrlParams(String url, String param, JSONObject bodyParams) {
        OutputStreamWriter out = null;
        BufferedReader in = null;
        StringBuilder result = new StringBuilder();
        try {
            String urlNameString = url + "?" + param;
            log.info("sendPostUrlParams - {}", urlNameString);
            URL realUrl = new URL(urlNameString);
            URLConnection conn = realUrl.openConnection();
            conn.setRequestProperty("accept", "*/*");
            conn.setRequestProperty("connection", "Keep-Alive");
            conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
            conn.setRequestProperty("Accept-Charset", "utf-8");
            conn.setRequestProperty("contentType", "utf-8");
            conn.setDoOutput(true);
            conn.setDoInput(true);
            if (bodyParams != null && !bodyParams.isEmpty()) {
                out = new OutputStreamWriter(conn.getOutputStream());
                out.write(bodyParams.toString());
                out.flush();
            }
            in = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"));
            String line;
            while ((line = in.readLine()) != null) {
                result.append(line);
            }
            log.info("recv - {}", result);
        } catch (ConnectException e) {
            log.error("调用HttpUtils.sendPost ConnectException, url=" + url + ",param=" + param, e);
        } catch (SocketTimeoutException e) {
            log.error("调用HttpUtils.sendPost SocketTimeoutException, url=" + url + ",param=" + param, e);
        } catch (IOException e) {
            log.error("调用HttpUtils.sendPost IOException, url=" + url + ",param=" + param, e);
        } catch (Exception e) {
            log.error("调用HttpsUtil.sendPost Exception, url=" + url + ",param=" + param, e);
        } finally {
            try {
                if (out != null) {
                    out.close();
                }
                if (in != null) {
                    in.close();
                }
            } catch (IOException ex) {
                log.error("调用in.close Exception, url=" + url + ",param=" + param, ex);
            }
        }
        return result.toString();
    }

    /**
     * @author: chenxiao
     * @description: 获取小程序二维码
     * @date: Create in 2023/6/9 14:31
     * @modified By:
     */
    public static String sendPostWXCode(String url, String param, JSONObject bodyParams) {
        OutputStreamWriter out = null;
        String result = "";
        try {
            String urlNameString = url + "?" + param;
            log.info("sendPostUrlParams - {}", urlNameString);
            URL realUrl = new URL(urlNameString);
            URLConnection conn = realUrl.openConnection();
            conn.setRequestProperty("accept", "*/*");
            conn.setRequestProperty("connection", "Keep-Alive");
            conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
            conn.setRequestProperty("Accept-Charset", "utf-8");
            conn.setRequestProperty("contentType", "utf-8");
            conn.setDoOutput(true);
            conn.setDoInput(true);
            if (bodyParams != null && !bodyParams.isEmpty()) {
                out = new OutputStreamWriter(conn.getOutputStream());
                out.write(bodyParams.toString());
                out.flush();
            }
            result = new String(Base64.getEncoder().encode(IOUtils.toByteArray(conn.getInputStream())), Charsets.UTF_8);
            log.info("recv - {}", result);
        } catch (ConnectException e) {
            log.error("调用HttpUtils.sendPost ConnectException, url=" + url + ",param=" + param, e);
        } catch (SocketTimeoutException e) {
            log.error("调用HttpUtils.sendPost SocketTimeoutException, url=" + url + ",param=" + param, e);
        } catch (IOException e) {
            log.error("调用HttpUtils.sendPost IOException, url=" + url + ",param=" + param, e);
        } catch (Exception e) {
            log.error("调用HttpsUtil.sendPost Exception, url=" + url + ",param=" + param, e);
        } finally {
            try {
                if (out != null) {
                    out.close();
                }
            } catch (IOException ex) {
                log.error("调用io close Exception, url=" + url + ",param=" + param, ex);
            }
        }
        return result;
    }
}

 

application.yml:

wx:
  # 微信公众平台 - 设置 - 开发设置」页中获得
  appid: xxx
  # 微信公众平台 - 设置 - 开发设置」页中获得
  secret: xxx
  # getAccessToken接口需要
  grantType: client_credential
  # 获取手机号
  getPhoneNumber: https://api.weixin.qq.com/wxa/business/getuserphonenumber
  # 获取小程序二维码
  getQRCode: https://api.weixin.qq.com/cgi-bin/wxaapp/createwxaqrcode
  # 获取小程序全局唯一后台接口调用凭据,token有效期为7200s
  getAccessToken: https://api.weixin.qq.com/cgi-bin/token
  numberTimeOut: 10

按照以上代码复制到项目即可,亲测可用的哈,有问题可以联系我噢

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

柠檬不萌c

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值