前言:
本文章将讨论如何实现目前小程序中普遍的微信授权获取用户信息进行登录/注册(当未注册的时候直接进行注册并登录)
API
我们先看看uni-app和微信小程序中为我们提供的几个API:
wx.login
/uni.login
: 获取临时登录凭证code,通过微信接口服务获取openId
https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/login.html
https://uniapp.dcloud.io/api/plugins/login?id=login
Openid,是每个小程序对于每个用户的唯一用户身份标识,通过数据库中记录openid,我们能够通过openid获取到对应的用户数据。
getPhoneNumber
: 获取用户手机号
https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/getPhoneNumber.html
这个比较特殊,通过下图的代码示例中我们可以看到这是button的一个属性
uni.getUserProfile
:获取用户信息。每次请求都会弹出授权窗口,用户同意后返回 userInfo。
https://uniapp.dcloud.io/api/plugins/login?id=getuserprofile
前端
虽然作者的项目是基于Jeecg实现的,但是在实战案例中,尽可能的参照原生API进行示范
- 首先是前端界面
login.vue
,我们通过uni-app的onLoad(对应vue的created)生命周期来进行wx.login操作
export default {
data() {
loginModel:{}
}
},
onLoad: function() {
let that = this //获取当前vue实例, uni.login.success中无法调用this
// 获取code
uni.login({
success(res) {
if (res.code) {
that.loginModel.code=res.code
console.log('tempCode:', that.loginModel.code)
} else {
console.log('登录失败!' + res.errMsg)
}
}
})
}
这样,我们就能够在进入登录页面后获取到用户的临时登录code。
接着我们需要一个button来拉起用户的授权操作,而获取用户的手机号和用户信息是两个不同的API,所以作者的解决方案是一次点击拉起两次授权:
<button open-type="getPhoneNumber" @getphonenumber="getPhoneNumber" @tap="getUserProfile">授权登录</button>
button中定义了三个属性opent-type
标识该button的类型告知小程序这个button要获取手机号了,@getphonenumber="getPhoneNumber"
拉起手机号授权的回调方法,@tap="getUserProfile"
点击该按钮的时候触发的方法。
export default {
...
methods:{
getUserProfile(){
// 拉起用户信息授权框,会比手机号授权提前执行
uni.getUserProfile({
desc: '用于完善会员资料', // 声明获取用户个人信息后的用途,后续会展示在弹窗中,请谨慎填写
success: (res) => {
let userInfo = res.userInfo
this.loginModel.nickname = userInfo.nickName
this.loginModel.avatar = userInfo.avatarUrl
this.loginModel.province = userInfo.province
this.loginModel.sex = userInfo.gender
this.loginModel.city = userInfo.city
}
})
},
// 手机号授权回调方法
getPhoneNumber(e){
if(e.detail.iv){
// 因为微信对手机号码的安全性做的很好,所以这里只能获取到加密后的数据,还需要拿到后端解密
this.loginModel.iv = e.detail.iv
this.loginModel.encryptedData = e.detail.encryptedData
// 手机号授权是后执行的,所以授权成功后直接调用授权登录接口将this.loginModel传入
// 这里简化了代码直接发送http请求,而不是通过vuex的方法进行请求,因为后者能够将后端返回的数据进行存储比如token,userInfo等
console.log(this.loginModel)
uni.request({
url: '后端地址/authorizedLogin',
data: this.loginModel,
success: (res) => {
// 提示信息。。。
// 跳转页面。。。
}
})
}
},
基于此,一个简单版本的基于uni-app的微信授权登录/注册前端就实现啦。
看看loginModel里面的数据。
后端
紧接着就是后端的代码了,我们创建一个LoginController定义一个POST请求的/authorizedLogin
的接口如下
/**
* 微信小程序授权登录
*/
@PostMapping(value = "/wxAuthorizedLogin")
public Result<JSONObject> wxAuthorizedLogin(@RequestBody AppPhoneLoginModel model) throws Exception{
Result<JSONObject> result = new Result<JSONObject>();
// 通过code去微信的API服务中取到对应的openid和sessionKey
JSONObject jo = code2Session(model.getCode());
// 可能会出现code异常的情况所以抛出异常通过全局异常处理器返回给前端提示
if(jo.getString("errmsg") != null){
throw new BaseException(jo.getString("errmsg"));
}
//获取openid和phone
String sessionKey = jo.getString("session_key");
String openid = jo.getString("openid");
//通过sessionKey和前端getPhone的加密数据的Iv向量获取到用户的手机号
JSONObject userInfo = WxUtil.getUserInfo(model.getEncryptedData(), sessionKey, model.getIv());
String phone = userInfo.getString("phoneNumber");
SysUser user = sysUserService.getUserByPhone(phone);
// 当手机号查询不到用户时走注册逻辑
if(user == null){
user = registerUser(model, phone, openid);
}
// 。。。根据用户的用户名等生成token并返回
return Result.OK(token);
}
private SysUser registerUser(AppPhoneLoginModel model, String phone, String openid){
// 根据前端传入的用户信息 创建默认的用户信息其细节 自行定义只要创建出一个用户并使用userService存入数据库即可
SysUser registeringUser = buildDefaultUser(model, phone, openid);
sysUserService.addUser(registeringUser);
return registeringUser
}
以上就是基于uni-app实现最基本的微信授权登录和注册的前端+后端全部内容啦,笔者能力有限,无法保证实例完全正确,但是尽可能的以静态审查的方式保证代码无误,请谅解。