java开发⼩程序登录功能整体流程如下:- 1.获取code- 2.⽤步骤1获取到的临时code换取⽤户唯⼀标识OpenId和会话密钥 session_key- 3.获取⽤户⼿机号,进⾏登录请求参数:请求参数:属性类型默认值必填说明appid string是⼩程序 appIdsecret string是⼩程序 appSecretjs_code string是登录时获取的 codegrant_type string是授权类型,此处只需填写 authorization_code 返回值:属性类型说明openid string⽤户唯⼀标识session_key string会话密钥unionid string⽤户在开放平台的唯⼀标识符,在满⾜ UnionID 下发条件的情况下会返回,详见。
errcode number错误码errmsg string错误信息开发前准备(必须)appid:wx4c1d53****7a671appsecret:fc9f99c08dcb2a0****eb26376c65eae⼩程序代码:login.js// pages/login/login.wxml.jsconst app = getApp();Page({/*** 页⾯的初始数据*/data: {// 判断⼩程序的API,回调,参数,组件等是否在当前版本可⽤。
canIUse: wx.canIUse('button.open-type.getPhoneNumber'),wechat: '微信快捷登录',isShow: false},/*** ⽣命周期函数--监听页⾯加载*/onLoad: function (options) {// 从缓存中取⼿机号console.log("获取⼿机号!")try {var value = wx.getStorageSync('phoneNumber')if (value) { // 说明已登录跳转页⾯console.log("获取缓存:"+value)wx.navigateTo({url: '../login?param=' + value})}else{// 未登录显⽰微信授权页⾯this.setData({isShow: true})}} catch (e) {}// 解决第⼀次获取⼿机号失败问题wx.login({success: res => {if(res.code){console.log("code->", res.code)}}})},// 0.获取⼿机号授权getPhoneNumber: function(e) {// ⽤户拒绝授权if(e.detail.errMsg == "getPhoneNumber:fail user deny") {wx.showToast({icon: "none",title: '请允许获取⼿机号,否则功能不可⽤!',})return}// console.log("e->detail", e.detail)/// ⽤户允许授权// console.log("iv->", e.detail.iv); //包括敏感数据在内的完整⽤户信息的加密数据,需要解密// console.log("encryptedData->", e.detail.encryptedData); //加密算法的初始向量,解密需要⽤到/// 获取⼿机号// 1.获取临时登录凭证codewx.login({success: res => {if(res.code){this.code = res.code;console.log("code->", res.code)console.log("encryptedData->", encodeURIComponent(e.detail.encryptedData))console.log("iv->", e.detail.iv)this.getSessionKey(res.code, e.detail.encryptedData, e.detail.iv);}}})},// 2.访问登录凭证校验接⼝获取session_key(后续改成后台实现)getSessionKey: function(js_code, encryptedData, iv) {// 3. 解密获取⼿机号wx.request({url: 'http://localhost:8082/wechat/appletLogin',data: {'encryptedData': encodeURIComponent(encryptedData),//需要进⾏编码'iv': iv,'jscode': js_code},method: 'POST',header: {'content-type': 'application/json'}, // 设置请求的 headersuccess: function(data2) {console.log(data)if(data.resultCode == 200) {if(er.phone==undefined){// 获取⼿机号失败跳转到常规⽤户登录页⾯(通过webview)wx.navigateTo({url: '⽤户登录页'})return}// 存储数据到缓存wx.setStorage({key:"phoneNumber",data:er.phone})// 4.跳转页⾯}},fail: function(err) {console.log(err);wx.showToast({icon: "none",title: '获取⼿机号失败,请重试!',})}})},/*** ⽣命周期函数--监听页⾯初次渲染完成*/onReady: function () {},/*** ⽣命周期函数--监听页⾯显⽰*/onShow: function () {},/*** ⽣命周期函数--监听页⾯隐藏*/onHide: function () {},/*** ⽣命周期函数--监听页⾯卸载*/onUnload: function () {},/*** 页⾯相关事件处理函数--监听⽤户下拉动作*/onPullDownRefresh: function () {},/*** 页⾯上拉触底事件的处理函数*/onReachBottom: function () {},/*** ⽤户点击右上⾓分享*/onShareAppMessage: function () {}})login.json{"usingComponents": {}}login.wxml<!--pages/login.wxml--><view class="modal-mask" catchtouchmove="preventTouchMove" wx:if="{{isShow}}"></view> <view class="modal-dialog" wx:if="{{isShow}}"><view class="modal-content"><view><image src='../images/show.png' class='show'></image></view><!-- <view>绑定⼿机号</view><view>请先绑定⼿机号在进⾏此操作</view> --><button class="show" type="primary" lang="zh_CN"open-type='getPhoneNumber' bindgetphonenumber="getPhoneNumber" >微信⽤户⼀键登录</button></view></view>login.wxss/* pages/login/login.wxml.wxss */.show{display: block;border-radius: 8rpx;margin: 20rpx 20rpx 20rpx 20rpx;font-size: 35rpx;}.container{position: fixed; /*关键属性,设置为fixed*/display: flex;flex-direction: column;width: 100%;height: 100%;}后端代码WxLoginController.java@RestController@RequestMapping("/wechat")public class WxLoginController {private Logger logger = LoggerFactory.getLogger(WxLoginController.class);@AutowiredUserDao userDao;@Value("${wechat.appid}")private String appid;@Value("${wechat.appsecret}")private String appsecret;private Map<String, Object> userMap = new HashMap<>();public ResultBean appletLogin(String encryptedData, String iv, String jscode) {System.out.println(encryptedData);ResultBean resultBean = new ResultBean();// jscodeif (StringUtils.isEmpty(jscode)) {resultBean.setResultCode(-10001);resultBean.setResultMessage("鉴权失败!");return resultBean;}// signif (StringUtils.isEmpty(encryptedData)) {resultBean.setResultCode(-10001);resultBean.setResultMessage("鉴权失败!");return resultBean;}if(StringUtils.isBlank(iv)) {resultBean.setResultCode(-10002);resultBean.setResultMessage("鉴权失败!");return resultBean;}// 创建Httpclient对象CloseableHttpClient httpclient = HttpClients.createDefault();String resultString = "";CloseableHttpResponse response = null;String url =WxContants.url.replace(WxContants.APPID, appid).replace(WxContants.SECRET, appsecret).replace(WxContants.JSCODE, jscode);try {// 创建uriURIBuilder builder = new URIBuilder(url);URI uri = builder.build();// 创建http GET请求HttpGet httpGet = new HttpGet(uri);// 执⾏请求response = httpclient.execute(httpGet);// 判断返回状态是否为200if (response.getStatusLine().getStatusCode() == 200) {resultString = EntityUtils.toString(response.getEntity(), "UTF-8");}} catch (Exception e) {e.printStackTrace();}// 解析jsonJSONObject jsonObject = (JSONObject) JSONObject.parse(resultString);String session_key = jsonObject.getString("session_key");String openid = jsonObject.getString("openid");System.out.println("session_key:"+session_key + ",openid:"+openid);if (StringUtils.isEmpty(session_key)) {resultBean.setResultCode(-10003);resultBean.setResultMessage("获取sessionkey失败!");return resultBean;}// 解码try {encryptedData = URLDecoder.decode(encryptedData,"UTF-8");} catch (UnsupportedEncodingException e) {logger.error("encryptedData,decode失败!", e);resultBean.setResultCode(-10003);resultBean.setResultMessage("encryptedData,decode失败!");return resultBean;}String decryptData = WechatDecryptDataUtil.decryptData(encryptedData, session_key, iv); JSONObject userInfo = JSONObject.parseObject(decryptData);// 存⼊redis+数据库,判断是否存在redis中,存在直接从redis返回// 本地使⽤Map模拟if (!userMap.containsKey(openid)) {// 判断⽤户是否存在系统中String phoneNumber = userInfo.getString("phoneNumber");User user = userDao.findByPhone(phoneNumber);if (user == null) {resultBean.setResultCode(200);resultBean.setResultMessage("此⽤户不存在,请先注册!");return resultBean;}user.setOpenId(openid);userDao.save(user);userMap.put(openid, user);}User user = (User) userMap.get(openid);resultBean.setResultCode(200);resultBean.setResultMessage("成功!");resultBean.setData(user);return resultBean;}}UserDao.javapublic interface UserDao extends JpaRepository<User, Long> {User findByPhone(String phone);User findByOpenId(String openId);}User.java@Entity@Table(name = "user")public class User {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id;private String openId;private String phone;public Long getId() {return id;}public void setId(Long id) {this.id = id;}public String getOpenId() {return openId;}public void setOpenId(String openId) {this.openId = openId;}public String getPhone() {return phone;}public void setPhone(String phone) {this.phone = phone;}}WechatDecryptDataUtil.javapublic class WechatDecryptDataUtil {private static Logger logger = LogManager.getLogger(WechatDecryptDataUtil.class);public static void main(String[] args) {String result = decryptData("BLY05rL1qLzGdqn+m4s4KfnM9CbMCm2sTZmgIcUJUpoOVeZkKKYh06ATVm2BgX8HUsH1a93811fhwr70MTh2Pk2qw9rPBzvos3husUJdVfaZgBk3Afp6wNFS0/kcoyt+7q2eMrIHMe6wkc4J0hgbbkxdUwZag/pyKXwe4pUzSQfta7dfBHy3DLu+REvwHiDNf "C9Z59YjFkCDT8+9NQ3OxcA==","oOWTpbZ80evG/GQqRdUu3w==");System.out.println("result = " + result);}public synchronized static String decryptData(String encryptDataB64, String sessionKeyB64, String ivB64) {String res = null;try {res = new String(decryptOfDiyIV(Base64.decode(encryptDataB64),Base64.decode(sessionKeyB64),Base64.decode(ivB64)));} catch (Exception e) {logger.error("encryptDataB64:"+encryptDataB64+"\n"+"sessionKeyB64:"+sessionKeyB64+"\n"+"ivB64:"+ivB64);}return res;}private static final String KEY_ALGORITHM = "AES";private static final String ALGORITHM_STR = "AES/CBC/PKCS7Padding";private static Key key;private static Cipher cipher;private static void init(byte[] keyBytes) {// 如果密钥不⾜16位,那么就补⾜. 这个if 中的内容很重要int base = 16;if (keyBytes.length % base != 0) {int groups = keyBytes.length / base + (keyBytes.length % base != 0 ? 1 : 0);byte[] temp = new byte[groups * base];Arrays.fill(temp, (byte) 0);System.arraycopy(keyBytes, 0, temp, 0, keyBytes.length);keyBytes = temp;}// 初始化Security.addProvider(new BouncyCastleProvider());// 转化成JAVA的密钥格式key = new SecretKeySpec(keyBytes, KEY_ALGORITHM);try {// 初始化ciphercipher = Cipher.getInstance(ALGORITHM_STR, "BC");} catch (Exception e) {e.printStackTrace();}}/*** 解密⽅法** @param encryptedData 要解密的字符串* @param keyBytes 解密密钥* @param ivs ⾃定义对称解密算法初始向量 iv* @return 解密后的字节数组*/private static byte[] decryptOfDiyIV(byte[] encryptedData, byte[] keyBytes, byte[] ivs) {byte[] encryptedText = null;init(keyBytes);try {cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(ivs));encryptedText = cipher.doFinal(encryptedData);} catch (Exception e) {e.printStackTrace();}return encryptedText;}}WxContants.javapublic interface WxContants {String APPID = "APPID";String SECRET = "SECRET";String JSCODE = "JSCODE";String TRADE_TYPE = "JSAPI";String url = "https:///sns/jscode2session?appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code";}。