开发小程序手机号授权需要到微信公众平台:
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
按照以上代码复制到项目即可,亲测可用的哈,有问题可以联系我噢