uni-app开发经验分享二十: 微信小程序 授权登录 获取详细信息 获取手机号
授权页面
因为微信小程序提供的 权限弹窗 只能通用户确认授权 所以可以 写一个授权页面,让用户点击 来获取用户相关信息 然后再配合后台就可以完成登录
<button class="btnInfo" open-type="getUserInfo"/>

素材

页面代码示例
这个接口要在后端调用(https://api.weixin.qq.com无法加入白名单)
https://api.weixin.qq.com/sns/jscode2session?appid="+appid+"&secret="+secret+"&js_code="+code+"&grant_type=authorization_code
<template>
<view>
<view>
<view>
<view class='header'>
<image src='../../static/wx_login.png'></image>
</view>
<view class='content'>
<view>申请获取以下权限</view>
<text>获得你的公开信息(昵称,头像、地区等)</text>
</view>
<!-- withCredentials=true 获取到除用户基本信息之外的encryptedData以及iv等数据 -->
<button class='bottom' type='primary' open-type="getUserInfo" withCredentials="true" lang="zh_CN" @getuserinfo="wxGetUserInfo">
授权登录
</button> <!-- <button class='bottom' type='primary' open-type="getPhoneNumber" @getphonenumber="getPhoneNumber">
授权登录
</button> -->
</view>
</view>
</view>
</template> <script>
import { htxcx } from "@/store/api.js"
import { mapMutations } from 'vuex'
export default {
data() {
return {
code:"",
SessionKey: '',
encryptedData:"",
iv:"",
OpenId: '',
nickName: null,
avatarUrl: null,
isCanUse: uni.getStorageSync('isCanUse')//默认为true 记录当前用户是否是第一次授权使用的
}
}, onLoad() {
this.login()
},
methods: {
...mapMutations(["setName"]),
wxGetUserInfo(){ //第一授权获取用户信息===》按钮触发
let _this = this;
// 获取用户信息
uni.getUserInfo({
provider: 'weixin',
success: function (infoRes) {
_this.encryptedData = infoRes.encryptedData
_this.iv = infoRes.iv
_this.nickName = infoRes.userInfo.nickName; //昵称
_this.avatarUrl = infoRes.userInfo.avatarUrl; //头像
uni.setStorageSync('isCanUse', false);//记录是否第一次授权 false:表示不是第一次授权
_this.updateUserInfo();
},fail:function (fail){console.log("fail:",fail)}
});
},
login(){
let _this = this;
uni.showLoading({
title: '登录中...'
}); // 1.wx获取登录用户code
uni.login({
provider: 'weixin',
success: function(loginRes) {
_this.code = loginRes.code;
if (!_this.isCanUse) {
//非第一次授权获取用户信息
uni.getUserInfo({
provider: 'weixin',
success: function(infoRes) {
console.log('login用户信息:',infoRes);
//获取用户信息后向调用信息更新方法
_this.nickName = infoRes.userInfo.nickName; //昵称
_this.avatarUrl = infoRes.userInfo.avatarUrl; //头像
_this.updateUserInfo();//调用更新信息方法
}
});
}
// 将用户登录code传递到后台置换用户SessionKey、OpenId等信息 uni.hideLoading();
},
}) },
updateUserInfo(){ //向后台更新信息
this.setName(this.nickName,this.avatarUrl)
let _this = this;
var obj ={
appid:"wx1*********0f06",
secret:"07bd3*************096",
code:this.code
}
// 这个接口要在后端调用(https://api.weixin.qq.com无法加入白名单)
// https://api.weixin.qq.com/sns/jscode2session?appid="+appid+"&secret="+secret+"&js_code="+code+"&grant_type=authorization_code
// 请求微信端地址获取用户唯一标识的
htxcx(obj.appid,obj.secret,obj.code).then(res=>{
console.log("res:",res) res.data.openid // 唯一
res.data.session_key
this.encryptedData
this.iv uni.reLaunch({//信息更新成功后跳转到小程序首页
url: '/pages/index/index'
});
},err=>{
console.log("err:",err)
}) }
}
}
</script> <style scoped>
.header {
margin: 90rpx 0 90rpx 50rpx;
border-bottom: 1px solid #ccc;
text-align: center;
width: 650rpx;
height: 300rpx;
line-height: 450rpx;
} .header image {
width: 200rpx;
height: 200rpx;
} .content {
margin-left: 50rpx;
margin-bottom: 90rpx;
} .content text {
display: block;
color: #9d9d9d;
margin-top: 40rpx;
} .bottom {
border-radius: 80rpx;
margin: 70rpx 50rpx;
font-size: 35rpx;
}
</style>
获取手机号
微信文档:https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/getPhoneNumber.html
前提条件 先要登录
onLoad() {
this.login()
},
还是用上面的授权页面
<button class='bottom' type='primary' open-type="getUserInfo" withCredentials="true" lang="zh_CN" @getuserinfo="wxGetUserInfo">授权登录</button> <button class='bottom' type='primary' open-type="getPhoneNumber" @getphonenumber="getPhoneNumber">获取手机号</button> 事件
getPhoneNumber(val){
console.log(val)
},
这个需要 真机测试 或 预览

<template>
<view>
<view>
<view>
<view class='header'>
<image src='../../static/wx_login.png'></image>
</view>
<view class='content'>
<view>申请获取以下权限</view>
<text>获得你的公开信息(昵称,头像、地区等)</text>
</view>
<!-- withCredentials=true 获取到除用户基本信息之外的encryptedData以及iv等数据 -->
<!-- <button class='bottom' type='primary' open-type="getUserInfo" withCredentials="true" lang="zh_CN" @getuserinfo="wxGetUserInfo">
授权登录
</button> --> <button class='bottom' type='primary' open-type="getPhoneNumber" @getphonenumber="getPhoneNumber">
授权登录
</button>
</view>
</view>
</view>
</template> <script> import { htxcx } from "@/store/api.js"
import { mapMutations } from 'vuex'
export default {
data() {
return {
code:"",
SessionKey: '',
encryptedData:"",
iv:"",
OpenId: '',
nickName: null,
avatarUrl: null,
isCanUse: uni.getStorageSync('isCanUse')//默认为true 记录当前用户是否是第一次授权使用的
}
}, onLoad() {
this.login()
},
methods: { ...mapMutations(["setName"]),
wxGetUserInfo(){ //第一授权获取用户信息===》按钮触发
let _this = this;
// 获取用户信息
uni.getUserInfo({
provider: 'weixin',
success: function (infoRes) {
_this.encryptedData = infoRes.encryptedData
_this.iv = infoRes.iv
_this.nickName = infoRes.userInfo.nickName; //昵称
_this.avatarUrl = infoRes.userInfo.avatarUrl; //头像
uni.setStorageSync('isCanUse', false);//记录是否第一次授权 false:表示不是第一次授权
_this.updateUserInfo();
},fail:function (fail){console.log("fail:",fail)}
});
},
getPhoneNumber:function(e){
this.encryptedData = e.detail.encryptedData
this.iv = e.detail.iv
uni.setStorageSync('isCanUse', false);
this.updateUserInfo()
},
login(){
let _this = this;
uni.showLoading({
title: '登录中...'
}); // 1.wx获取登录用户code
uni.login({
provider: 'weixin',
success: function(loginRes) {
console.log("登录",loginRes.code)
_this.code = loginRes.code;
if (!_this.isCanUse) {
//非第一次授权获取用户信息
uni.getUserInfo({
provider: 'weixin',
success: function(infoRes) {
console.log('login用户信息:',infoRes);
//获取用户信息后向调用信息更新方法
_this.nickName = infoRes.userInfo.nickName; //昵称
_this.avatarUrl = infoRes.userInfo.avatarUrl; //头像
_this.updateUserInfo();//调用更新信息方法
},
fail(err) {
console.log(err)
}
});
}
// 将用户登录code传递到后台置换用户SessionKey、OpenId等信息 uni.hideLoading();
},
}) },
updateUserInfo(){ //向后台更新信息
this.setName(this.nickName,this.avatarUrl)
let _this = this;
var obj ={
appid:"wx1b02a26b03110f06",
secret:"07bd35d41e7fb6a9bff173c728d6a096",
code:this.code
} // 这一步一般是在后台 这里是为了测试
// 正常给 后台 5个测试 appId appsecret code(登录接口获取) encryptedData iv htxcx(obj.appid,obj.secret,obj.code).then(res=>{
console.log("res:",res) res.data.openid // 唯一
res.data.session_key
this.encryptedData
this.iv // 把这些参数通过接口传给后台 解密 获取手机号 return
uni.reLaunch({//信息更新成功后跳转到小程序首页
url: '/pages/index/index'
});
},err=>{
console.log("err:",err)
})
}
}
}
</script>
至于后台解密
我的项目后台解密
package jstfsn; import java.io.UnsupportedEncodingException;
import java.security.Security;
import java.security.spec.AlgorithmParameterSpec;
import java.sql.Connection;
import java.text.ParseException; import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import javax.naming.NamingException; import org.apache.commons.codec.binary.Base64;
import org.apache.log4j.Logger; import GCcom.CommonValue;
import GCcom.DBOperation;
import StxsysBass.StxsysAdmin.CheckingLineService;
import com.alibaba.fastjson.JSONObject;
import com.justep.baas.action.ActionContext; public class Login { /**
* 查询历史线路未巡检的巡检点
*
* @param params
* @param context
* @return
* @throws NamingException
*/ /**
* 日志
*/
public static Logger logger = Logger.getLogger(CheckingLineService.class);
/**
* 数据库名
*/
// public static String DATASOURCE = CommonValue.MYSQL_DATA_BASE_JSTFSN; /************************************************************************************
* 函数名: getWxUserInfo
* 参数名: JSONObject params: 参数集
* ActionContext context : 上下文
*
* 功能: 通过用户授权加密信息解密获取用户信息
*
* 开发者: Leechen8@gmail.com 20200317
*
* 修改者:
*
* @return
* @throws ParseException
*
*
************************************************************************************/
public static JSONObject getWxUserInfo(JSONObject params, ActionContext context) throws NamingException {
// 获取参数
String strCipher = "";
String strEncrypdata = params.getString("encrypdata");
String strIvdata = params.getString("ivdata");
String strSessionkey= params.getString("sessionkey"); byte[] byEncrypdata = Base64.decodeBase64(strEncrypdata);
byte[] byIvdata = Base64.decodeBase64(strIvdata);
byte[] bySessionkey = Base64.decodeBase64(strSessionkey); JSONObject jsData = new JSONObject(); AlgorithmParameterSpec ivSpec = new IvParameterSpec(byIvdata);
Cipher cipher;
try {
SecretKeySpec keySpec = new SecretKeySpec(bySessionkey, "AES");
cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
strCipher = new String(cipher.doFinal(byEncrypdata),"UTF-8");
jsData.put("phone", strCipher); } catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
jsData.put("error", e.getMessage());
} return jsData;
} }
可参考 https://blog.csdn.net/qq_38194393/article/details/81382108
获取详细信息 获取手机号 优化封装
页面
<template>
<view>
<view>
<view>
<view class='header'>
<image src='../../static/wx_login.png'></image>
</view>
<view class='content'>
<view>申请获取以下权限</view>
<text>获得你的公开信息(昵称,头像、地区等)</text>
<text>获得你微信绑定的手机号</text>
</view> <!-- <picker class="view_input" @change="bindPickerMPChange" :value="type" :range="typeArr">
<view :class="typeArr[type]?'uni-input':'uni-input options'">{{typeArr[type]? typeArr[type]:"请选择用户身份"}}</view>
</picker> --> <button class='bottom' type='primary' open-type="getUserInfo" withCredentials="true" lang="zh_CN" @getuserinfo="wxGetUserInfo">
授权登录
</button> <button class='bottom' type='primary' open-type="getPhoneNumber" @getphonenumber="getPhoneNumber">
手机号授权
</button>
</view>
</view>
</view>
</template> <script>
import {wxlogin, getPhone, wxUserInfo} from "@/store/wxlogin.js"
import {htxcx} from "@/store/api.js"
export default {
data() {
return {
appid:"wx1b02a26b03110f06",
secret:"07bd35d41e7fb6a9bff173c728d6a096",
type:0,
phone:"",
typeArr:["承运人","管理员"],
phoneParams:{
sessionkey:"",
ivdata:"",
encrypdata:""
},
loginStatus:false,
phoneStatus:false
}
},
onLoad() {
try{
this.init()
}catch(e){
console.log("init错误信息:",e)
}
},
methods: {
async init(){
var code = await wxlogin()
// 获取sessionkey
var key = await htxcx(this.appid,this.secret,code)
this.phoneParams.sessionkey = key.data.session_key;
},
async getPhoneNumber(e){
this.phoneParams.encrypdata = e.detail.encryptedData
this.phoneParams.ivdata = e.detail.iv var phone = await getPhone(this.phoneParams)
this.phone = phone.purePhoneNumber
console.log("phone:",this.phone) if(this.phone){
this.phoneStatus = true
this.reLaunch()
}
},
async wxGetUserInfo(){
var info = await wxUserInfo()
this.loginStatus = true
this.reLaunch()
},
reLaunch(){
if(this.loginStatus && this.phoneStatus){
uni.setStorageSync("tongfang-phone",this.phone) // 后续业务代码 // uni.reLaunch({//信息更新成功后跳转到小程序首页
// url: '/pages/index/index'
// });
}
}, bindPickerMPChange(e){
this.type = e.target.value
}
}
}
</script> <style>
.header {
margin: 90rpx 0 50rpx 50rpx;
border-bottom: 1px solid #ccc;
text-align: center;
width: 650rpx;
height: 300rpx;
line-height: 450rpx;
}
.header image {
width: 200rpx;
height: 200rpx;
}
.content {
margin-left: 50rpx;
margin-bottom: 50rpx;
}
.content text {
display: block;
color: #9d9d9d;
margin-top: 40rpx;
}
.bottom {
border-radius: 80rpx;
margin: 35rpx 50rpx;
font-size: 35rpx;
}
.bottom:first-child{
margin-top: 50rpx;
} .view_input{
margin: 0 50rpx;
background-color: white;
padding: 10px;
height: 1rem;
line-height: 1rem;
}
</style>
wxlogin.js
import {getPhone as getphone} from '@/store/api.js'
/*
微信登录
返回 code
*/
export const wxlogin = ()=> {
return new Promise((resolve, reject)=>{
uni.showLoading({
title: '登录中...'
});
uni.login({
provider: 'weixin',
success: function(loginRes) {
resolve(loginRes.code);
uni.hideLoading();
},
fail(err) {
reject(err)
uni.hideLoading();
}
})
})
}
/*
获取微信用户信息 要先调用登录接口
返回用户信息
*/
export const wxUserInfo = ()=>{
return new Promise((resolve, reject)=>{
uni.getUserInfo({
provider: 'weixin',
success: function(res) {
resolve(res);
},
fail(err) {
reject(err)
}
});
})
}
/*
获取微信用户手机号 要先调用登录接口
参数:obj{
sessionkey,
ivdata,
encrypdata
}
返回手机号相关信息
*/
export const getPhone = (obj)=>{
return new Promise((resolve, reject)=>{
getphone(obj).then(res=>{
resolve(JSON.parse(res.data.data.phone))
},err=>{
reject(err)
})
})
}
api.js
// 接口获取 sessionkey
export const htxcx = (appid,secret,code)=>uniAjax("https://api.weixin.qq.com/sns/jscode2session?appid="+appid+"&secret="+secret+"&js_code="+code+"&grant_type=authorization_code") // 解密手机号
export const getPhone = (obj)=>uniAjax(BASE_URL_dev+"/getWxUserInfo",obj,"POST")
转载于:https://blog.csdn.net/weixin_42448623/article/details/104928750
uni-app开发经验分享二十: 微信小程序 授权登录 获取详细信息 获取手机号的更多相关文章
- 微信小程序授权登录以及用户信息相关接口调整导致授权框不弹出
前言:4月8号升级了小程序业务后提交了版本并上线.突然一个同事说体验版的点击"登录"按钮无效.当时觉得应该不会呀,这几天一直用手机调试,每天也在不停的登录授权,弹框一直有的呀.然后 ...
- 完整微信小程序授权登录页面教程
完整微信小程序授权登录页面教程 1.前言 微信官方对getUserInfo接口做了修改,授权窗口无法直接弹出,而取而代之是需要创建一个button,将其open-type属性绑定getUseInfo方 ...
- uni-app 微信小程序授权登录
1.微信小程序 获取用户信息 与获取手机号 详细信息看官方公告:https://developers.weixin.qq.com/community/develop/doc/000cacfa20ce8 ...
- 微信小程序授权登录将open_id传至后台并入库
要求能把用户昵称.头像以及open_id写入数据库,服务端保持用户登录状态 wxml: <block wx:else> <button type="primary" ...
- 微信小程序授权登录
目录 自定义授权页面 点击授权登录后出现微信自带的授权登录弹窗 <!--index.wxml--> <!-- 授权界面 --> <cover-view class='au ...
- 微信小程序API 登录-wx.login(OBJECT) + 获取微信用户唯一标识openid | 小程序
wx.login(OBJECT) 调用接口获取登录凭证(code)进而换取用户登录态信息,包括用户的唯一标识(openid) 及本次登录的 会话密钥(session_key).用户数据的加解密通讯需要 ...
- 微信小程序授权登录--PHP后端接口
由于之前做过公众号的一个开发,所以再开发小程序就没有那么多坑了,在这也记录一下开发过程,以方便后续进行参考. 废话不多说,直接上官方文档,任何使用第三方开发的,不看文档就是耍流氓.小程序开发文档,可以 ...
- day87_11_7微信小程序之登录,支付(获取ip,requests使用),授权
一.登录接口. 官方文档https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/login.html 在登录接口 ...
- 使用Shiro+JWT完成的微信小程序的登录(含讲解)
使用Shiro+JWT完成的微信小程序的登录 源码地址https://github.com/Jirath-Liu/shiro-jwt-wx 微信小程序用户登陆,完整流程可参考下面官方地址,本例中是按此 ...
随机推荐
- MyBatisPlus-常用注解
一.@TableName 映射数据库的表名 package com.md.entity; import com.baomidou.mybatisplus.annotation.*; import co ...
- netsniff恶意流量识别和匹配解读
代码整体框架 流量扫描函数调用 加载配置文件的代码调用 获取扫描的条数 重点匹配函数 流量eg:'\x00\x04\x00\x01\x00\x06\x00\x16>\x10\x1d>SW\ ...
- Stream并行流详解
1.并行与并发的区别 在说到并行的时候,相信很多人都会想到并发的概念.那么并行和并发两者一字之差,有什么区别呢? 并行:多个任务在同一时间点发生,并由不同的cpu进行处理,不互相抢占资源 并行: 并发 ...
- NET 5 使用RabbitMQ以及Kafka区别
区别 1.应用场景方面RabbitMQ:用于实时的,对可靠性要求较高的消息传递上.kafka:用于处于活跃的流式数据,大数据量的数据处理上.2.架构模型方面producer,broker,consum ...
- C#中未在本地计算机上注册“Microsoft.Jet.OLEDB.4.0”提供程序
解决方法 方法一 "设置应用程序池默认属性"/"常规"/"启用32位应用程序",设置为 true. 方法二 生成->配置管理器-> ...
- vs2010新特性
下面列出了一些新的功能:1.代码编辑器新的代码编辑器使代码更易于阅读.可以通过按 CTRL 并滚动鼠标轮放大文本.此外,单击 Visual C# 或 Visual Basic 中的符号时该符号的所有实 ...
- leetcode Add to List 31. Next Permutation找到数组在它的全排列中的下一个
直接上代码 public class Solution { /* 做法是倒着遍历数组,目标是找到一个数比它前边的数大(即这个数后边的是降序排列),如果找到了那么这个数前边的那个数就是需要改变的最高位, ...
- Qt学习笔记-启动一个额外的应用程序-获取输入的回车信号
现在让我们的程序模拟windows下的运用程序. 在命令行中输入命令.点击确定即可运行系统中的程序. 添加头文件#include <QProcess> 在确定按钮的响应函数中写上功能要求. ...
- jq 右键菜单在弹出菜单前如果需要显示与否的判断相关操作
菜单插件(ContextMenu)接收一个额外的参数对象来设置菜单项的样式和绑定鼠标事件. 菜单插件(ContextMenu)支持一下参数设置: bindings 包含id的对象:函数组. 当关联的菜 ...
- spark的 structStreaming 一些介绍
转发 https://www.toutiao.com/a6696339998905467403/?tt_from=mobile_qq&utm_campaign=client_share& ...