可以登录同主体的微信公众号,在小程序管理里面能够看到该主体下未注册完的公众号,你在那里删除就可以了。或者你可以在那里看一下小程序帐号,在微信公众平台登录一下,按照流程完成注册。
微信的想法:手机开机 —> 微信 —> (社交+购物+吃饭+金融...) —> 手机关机 —> 循环以上步骤别的公司的想法: 微信 —> 小程序 —> 获得粉丝 —> 完整版请下载APP但凡智商正常的公司决策人,会被微信捏着蛋么?
流程图
页面原型
微信一键登录
绑定用户手机号码
前台代码
index.wxml
<button class='phone-text' open-type="getUserInfo" lang="zh_CN" bindgetuserinfo="onGotUserInfo">请登录</button><!--登录弹窗--><view class="modal-mask" catchtouchmove="preventTouchMove" wx:if="{{showModal}}"></view> <view class="modal-dialog" wx:if="{{showModal}}"> <view class="modal-content"> <view><image src='../images/show.png' class='show'></image></view> <view>绑定手机号</view> <view>请先绑定手机号在进行此操作</view> <button open-type='getPhoneNumber' bindgetphonenumber="getPhoneNumber"> <image src='../images/showWx.png' class='iconWx'></image>微信用户一键绑定 </button> </view></view>
index.js
Page({ /** * 页面的初始数据 */ data: { openid: "", loginstate: "0", openid: "", userEntity: null, terminal: "", osVersion: "", phoneNumber: "", showModal: false,//定义登录弹窗 }, //在页面加载的时候,判断缓存中是否有内容,如果有,存入到对应的字段里 onLoad: function () { var that = this; wx.getStorage({ key: 'openid', success: function (res) { that.setData({ openid: res.data }); }, fail: function (res) { that.getcode(); } }); wx.getStorage({ key: 'userEntity', success: function (res) { that.setData({ userEntity: res.data }); }, fail: function (res) { console.log("fail1"); } }); wx.getStorage({ key: 'loginstate', success: function (res) { that.setData({ loginstate: res.data }); }, fail: function (res) { console.log("fail2"); } }); }, onGotUserInfo: function (e) { var that = this; if (e.detail.errMsg == "getUserInfo:ok") { wx.setStorage({ key: "userinfo", data: e.detail.userInfo }) this.setData({ userInfo: e.detail.userInfo }); that.showDialogBtn();//调用一键获取手机号弹窗(自己写的) } }, // 显示一键获取手机号弹窗 showDialogBtn: function () { this.setData({ showModal: true//修改弹窗状态为true,即显示 }) }, // 隐藏一键获取手机号弹窗 hideModal: function () { this.setData({ showModal: false//修改弹窗状态为false,即隐藏 }); }, onshow: function (openid, userInfo, phoneNumber) { var that = this; wx.getSystemInfo({ success: function (res) { that.setData({ terminal: res.model }); that.setData({ osVersion: res.system }); } }) wx.request({ url: '登录接口', method: 'POST', header: { 'content-type': 'application/json' // 默认值 }, data: { username: phoneNumber, parentuser: 'xudeihai', wximg: userInfo.avatarUrl, nickname: userInfo.nickName, identity: "", terminal: that.data.terminal, osVersion: that.data.system, logintype: "10",//微信登录 openid: that.data.openid, }, success(res) { if (res.data.r == "T") { that.setData({ userEntity: res.data.d }); wx.setStorage({ key: "userEntity", data: res.data.d }) that.setData({ loginstate: "1" }); wx.setStorage({ key: "loginstate", data: "1" }) wx.setStorage({ key: 'userinfo', data: "1" }) } else { return; } }, fail(res) { console.log(res); } }) }, //绑定手机 getPhoneNumber: function (e) { var that = this; that.hideModal(); wx.checkSession({ success: function () { wx.login({ success: res => { wx.request({ url: '自己的登录接口', //仅为示例,并非真实的接口地址 data: { account: '1514382701', jscode: res.code }, method: "POST", header: { 'content-type': 'application/json' // 默认值 }, success(res) { if (res.data.r == "T") { wx.setStorage({ key: "openid", data: res.data.openid }) wx.setStorage({ key: "sessionkey", data: res.data.sessionkey }) wx.setStorageSync("sessionkey", res.data.sessionkey); wx.request({ url: '自己的解密接口',//自己的解密地址 data: { encryptedData: e.detail.encryptedData, iv: e.detail.iv, code: wx.getStorageSync("sessionkey") }, method: "post", header: { 'content-type': 'application/json' }, success: function (res) { if (res.data.r == "T") { that.onshow(that.data.openid, that.data.userInfo, res.data.d.phoneNumber);//调用onshow方法,并传递三个参数 console.log("登录成功") console.log(res.data.d.phoneNumber)//成功后打印微信手机号 } else { console.log(res); } } }) } } }) } }) }, fail: function () { wx.login({ success: res => { wx.request({ url: '自己的登录接口', //仅为示例,并非真实的接口地址 data: { account: '1514382701', jscode: res.code }, method: "POST", header: { 'content-type': 'application/json' // 默认值 }, success(res) { if (res.data.r == "T") { wx.setStorage({ key: "openid", data: res.data.openid }) wx.setStorage({ key: "sessionkey", data: res.data.sessionkey }) wx.request({ url: '自己的解密接口',//自己的解密地址 data: { encryptedData: e.detail.encryptedData, iv: e.detail.iv, code: res.data.sessionkey }, method: "post", header: { 'content-type': 'application/json' }, success: function (res) { that.onshow(that.data.openid, that.data.userInfo, res.data.d.phoneNumber);//调用onshow方法,并传递三个参数 } }) } } }) } }) } }) },})
后台代码
接受code 信息调用微信获取openid
@ApiOperation("乘客微信一键登录") @PostMapping("/customer/loginByWeixin") public Result<JSONObject> loginByWeixin(@RequestParam(value = "code") String code, HttpServletRequest request) { Result<JSONObject> result = new Result<JSONObject>(); if (code == null) { result.setMessage("code不能为空!"); result.setSuccess(false); return result; } String sessionKey = null; String openId = null; try { WxMaJscode2SessionResult wxMaJscode2SessionResult = this.wxService.getUserService().getSessionInfo(code); sessionKey = wxMaJscode2SessionResult.getSessionKey(); openId = wxMaJscode2SessionResult.getOpenid(); } catch (Exception e) { e.printStackTrace(); result.setMessage("微信登录,调用官方接口失败!" + e.getMessage()); result.setSuccess(false); return result; } if (sessionKey == null || openId == null) { result.setMessage("微信登录,调用官方接口失败!"); result.setSuccess(false); return result; } LeUser user = leUserService.getUserByOpenid(openId); if (user == null) { //新用户注册 user = new LeUser(); user.setWeixinOpenid(openId); user.setPasswd(openId); user.setStatus(1); user.setLastLoginTime(new Date()); leUserService.save(user); } HashMap<String, String> wxsession = new HashMap<>(); wxsession.put("openid", openId); wxsession.put("sessionkey", sessionKey); //老用户登录 userInfo(user, result); return result; }
绑定用户信息
@AutoLog(value = "乘客解密用户信息&绑定用户信息") @ApiOperation(value = "乘客解密用户信息&绑定用户信息", notes = "乘客解密用户信息&绑定用户信息") @PostMapping(value = "/customer/bindUserinfo") public Result bindUserinfo(@RequestParam(value = "sessionKey") String sessionKey, @RequestParam(value = "encryptedData") String encryptedData, @RequestParam(value = "iv") String iv, HttpServletRequest request) { WxMaUserInfo userInfo = null; try { // 解密用户信息 userInfo = this.wxService.getUserService().getUserInfo(sessionKey, encryptedData, iv); } catch (Exception e) { e.printStackTrace(); return Result.error("解密用户信息失败!" + e.getMessage()); } LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal(); String userId = sysUser.getId(); LeUser user = leUserService.getById(userId); user.setNickname(userInfo.getNickName()); user.setUsername(userInfo.getNickName()); user.setAvatar(userInfo.getAvatarUrl()); user.setUsex(userInfo.getGender() == "女" ? 2 : 1); leUserService.updateById(user); return Result.OK(user); }
绑定乘客信息
@AutoLog(value = "乘客解密用户手机号码&绑定用户手机号码") @ApiOperation(value = "乘客解密用户手机号码&绑定用户手机号码", notes = "乘客解密用户手机号码&绑定用户手机号码") @PostMapping(value = "/customer/bindUserphone") public Result bindUserphone(@RequestParam(value = "sessionKey") String sessionKey, @RequestParam(value = "encryptedData") String encryptedData, @RequestParam(value = "iv") String iv, HttpServletRequest request) { WxMaPhoneNumberInfo phoneNumberInfo = null; try { // 解密用户信息 phoneNumberInfo = this.wxService.getUserService().getPhoneNoInfo(sessionKey, encryptedData, iv); } catch (Exception e) { e.printStackTrace(); return Result.error("解密用户信息失败!" + e.getMessage()); } LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal(); String userId = sysUser.getId(); LeUser user = leUserService.getById(userId); user.setMobile(phoneNumberInfo.getPhoneNumber()); leUserService.updateById(user); return Result.OK(user); }
作者:灰灰来源:JS每日一题
一、背景传统的web开发实现登陆功能,一般的做法是输入账号密码、或者输入手机号及短信验证码进行登录
服务端校验用户信息通过之后,下发一个代表登录态的 token 给客户端,以便进行后续的交互,每当token过期,用户都需要重新登录
而在微信小程序中,可以通过微信官方提供的登录能力方便地获取微信提供的用户身份标识,快速建立小程序内的用户体系,从而实现登陆功能
实现小程序用户体系主要涉及到openid和code的概念:
调用wx.login()方法会生成code,将code作为参数传递给微信服务器指定接口,就可以获取用户的openid对于每个小程序,微信都会将用户的微信ID映射出一个小程序 openid,作为这个用户在这个小程序的唯一标识
二、流程微信小程序登陆具体实现的逻辑如下图所示:
通过 wx.login() 获取到用户的code判断用户是否授权读取用户信息,调用wx.getUserInfo 读取用户数据由于小程序后台授权域名无法授权微信的域名,所以需要自身后端调用微信服务器获取用户信息通过 wx.request() 方法请求业务方服务器,后端把 appid , appsecret 和 code 一起发送到微信服务器。appid 和 appsecret 都是微信提供的,可以在管理员后台找到微信服务器返回了 openid 及本次登录的会话密钥 session_key后端从数据库中查找 openid ,如果没有查到记录,说明该用户没有注册,如果有记录,则继续往下走session_key 是对用户数据进行加密签名的密钥。为了自身应用安全,session_key 不应该在网络上传输然后生成 session并返回给小程序小程序把 session 存到 storage 里面下次请求时,先从 storage 里面读取,然后带给服务端服务端对比 session 对应的记录,然后校验有效期更加详细的功能图如下所示:
三、扩展实际业务中,我们还需要登录态是否过期,通常的做法是在登录态(临时令牌)中保存有效期数据,该有效期数据应该在服务端校验登录态时和约定的时间(如服务端本地的系统时间或时间服务器上的标准时间)做对比
这种方法需要将本地存储的登录态发送到小程序的服务端,服务端判断为无效登录态时再返回需重新执行登录过程的消息给小程
另一种方式可以通过调用wx.checkSession检查微信登陆态是否过期:
如果过期,则发起完整的登录流程
如果不过期,则继续使用本地保存的自定义登录态
这种方式的好处是不需要小程序服务端来参与校验,而是在小程序端调用AP,流程如下所示:
参考文献