微信小程序开发——微信授权登录

开发工具

前端 微信小程序开发工具
后端 idea 2018.3 +mysql8.0

后端技术栈 ----Springboot+mybatis

ps:因为我是后端开发 所以只能写后端。。

开发阶段

一 准备账号

邮箱注册微信公众平台小程序 !!! 着重强调 是小程序注册 !!!
注册链接:微信公众平台

注册完成之后 ,在开发-开发设置里边可以看到appid和secret,注册的目的就是为了获取这两个参数,以为了向微信服务器发送请求

微信小程序开发——微信授权登录_第1张图片

二 准备域名

因为微信平台的要求,需要用http:或者https:开头的合法域名,我这里采用的是natapp 购买的隧道,类似于服务器+域名(9RMB一个月,作为调试开发还是可以的) ,然后将域名配置到微信的开发-开发设置里边
微信小程序开发——微信授权登录_第2张图片
这里需要注意的是:前端访问的域名不能是服务器ip+端口号+接口名的方式,是要以这个request合法域名+接口名发送请求,否则请求不能发送到微信服务器端

三 代码实现

因为前端的同学跟我是第一次开发微信小程序,登录获取用户授权页面有点简陋,就不发wxml了(微信版html)

前端js代码

// pages/indxe/login/login.js
Page({

  /**
   * 页面的初始数据
   */
  data: {

  },
  getUserInfoBtn:function(){
  
    wx.login({
      success:function(data){
          var code=data.code
        wx.getUserInfo({
          success:function(res){
           var userInfor=res
            var rawData=res.rawData
            var iv=res.iv
            var encryptedData = res.encryptedData
            console.log(encryptedData)
            wx.request({
              url:'//微信要求的合法域名+后端请求接口'
              data: {
              
                iv:         iv,
                encryptedData: encryptedData,
                code:      code
              },
              header: {
                'content-type': 'application/json' //默认值
              },
              success: function (res) {
                console.log(res.data)
              }
            })
            
          }
        })
      }
    })
  },

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {

  },

  /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady: function () {

  },

  /**
   * 生命周期函数--监听页面显示
   */
  onShow: function () {

  },

  /**
   * 生命周期函数--监听页面隐藏
   */
  onHide: function () {

  },

  /**
   * 生命周期函数--监听页面卸载
   */
  onUnload: function () {

  },

  /**
   * 页面相关事件处理函数--监听用户下拉动作
   */
  onPullDownRefresh: function () {
http://wechatapptest.natapp1.cc/takeaway/user/login',
  },

  /**
   * 页面上拉触底事件的处理函数
   */
  onReachBottom: function () {

  },

  /**
   * 用户点击右上角分享
   */
  onShareAppMessage: function () {

  }
})

后端yml文件配置

spring:
  datasource:
    username: root
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/takeaway_applet?useSSL=false&characterEncoding=utf-8
    type: com.alibaba.druid.pool.DruidDataSource
    druid:
      # 初始化大小,最小,最大
      initial-size: 5
      min-idle: 5
      max-active: 50
      # 获取连接等待超时的时间
      max-wait: 60000
      # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
      time-between-eviction-runs-millis: 60000
      # 配置一个连接在池中最小生存的时间,单位是毫秒
      min-evictable-idle-time-millis: 300000

mybatis:
  mapper-locations: classpath:mappers/*.xml
  type-aliases-package: com.swpu.uchain.takeawayapplet.entity
  configuration:
    map-underscore-to-camel-case: true
    use-generated-keys: true

file:
  upload-dir: "/home/hobo/testFile"


#微信端配置
wechat:
  appid: wx08cbe6a7723b4059
  secret: 184d33fb3de278d49a1411cd111eeaa2

配置文件对应类

/**
 * @ClassName WeChatAccountConfig
 * @Author hobo
 * @Date 19-3-8 下午9:49
 * @Description
 **/
@Data
@ConfigurationProperties(prefix = "wechat")
@Component
public class WeChatProperties {


    /**
     * 微信小程序appId
     */
    private String appid;

    /**
     * 微信小程序的Secret
     */
    private String secret;

    /**
     * 微信小程序消息服务器配置的token
     */
    private String token;

    /**
     * 设置微信小程序消息服务器配置的EncodingAESKey
     */
    private String aesKey;

    /**
     * 消息格式,XML或者JSON
     */
    private String msgDataFormat;

    /**
     * 开放平台id
     */
    private String openAppId;

    /***
     * 开放平台秘钥
     */
    private String openAppSecret;
    /**
     * 商户号
     */
    private String mchId;

    /**
     * 商户密钥
     */
    private String mchKey;

    /**
     * 商户证书路径
     */
    private String keyPath;

    /**
     * 微信异步通知地址
     */
    private String notifyUrl;

    /**
     * 商品简单描述
     */
    private String title;

    /**
     * 支付类型 小程序为JSAPI
     */
    private String tradeType;

}

WXController

PS: 微信小程序登录分为两种,一种是前端在发送登录请求时,随机发送code,不需要用户授权,这种方式只获得用户的openId,另一种方式是从微信端发来iv,encryptedData,code。后端经过算法解密处理得到用户的一些信息,包括微信昵称及头像等等,我这次是采用了后者。根据前端代码大家也可以看出前端是传了这三个参数的。

    @ApiOperation("普通用户登录授权接口")
    @GetMapping(value = "/login", name = "普通用户登录")
    public Object getUserInfo(String encryptedData, String iv, String code) {
        Map map = new HashMap();
        if (code == null) {
            return ResultUtil.error(ResultEnum.CODE_EMPTY);
        }
        //微信登录请求URL
        String url = "https://api.weixin.qq.com/sns/jscode2session?appid=" + weChatProperties.getAppid() + "&secret=" + weChatProperties.getSecret() + "&js_code=" + code + "&grant_type=authorization_code";
        RestTemplate restTemplate = new RestTemplate();
        String response = restTemplate.getForObject(url, String.class);
        //将Json对象转换为Java对象
        WeChatVO weChatVO = JSONObject.parseObject(response, WeChatVO.class);
        String openId = weChatVO.getOpenId();
        String sessionKey = weChatVO.getSessionKey();

        //解密用户信息
        String result = AesCbcUtil.decrypt(encryptedData, sessionKey, iv, "UTF-8");
        if (null != result && result.length() > 0) {
            //ResultUtil是我自定义的Json化工具类
            return ResultUtil.success(result);

        }
        return ResultUtil.error(ResultEnum.DECRYPTION_FAILURE);
    }

解密工具类

需要引入bcprov-ext-jdk16的依赖

       
            org.bouncycastle
            bcprov-ext-jdk16
            1.46
            jar
        
import org.apache.commons.codec.binary.Base64;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.*;
import java.security.spec.InvalidParameterSpecException;

/**
 * @ClassName AesCbcUtil
 * @Author hobo
 * @Date 19-3-15 下午3:15
 * @Description 用于用户解密
 **/
public class AesCbcUtil {

    static {
        Security.addProvider(new BouncyCastleProvider());
    }

    /**
     * @return java.security.Security
     * @Author hobo
     * @Description :   AES解密
     * @Param data             //密文 加密的数据
     * @Param key              //秘钥
     * @Param iv               //偏移量
     * @Param encodingFormat   //解密后结果的编码格式
     **/
    public static String decrypt(String data, String key, String iv, String encodingFormat) {

        byte[] dataByte = Base64.decodeBase64(data);
        byte[] keyByte = Base64.decodeBase64(key);
        byte[] ivByte = Base64.decodeBase64(iv);

        try {
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
            SecretKeySpec spec = new SecretKeySpec(keyByte, "AES");

            AlgorithmParameters parameters = AlgorithmParameters.getInstance("AES");
            parameters.init(new IvParameterSpec(ivByte));

            cipher.init(Cipher.DECRYPT_MODE, spec, parameters);
            byte[] resultByte = cipher.doFinal(dataByte);
            if (null != resultByte && resultByte.length > 0) {
                String result = new String(resultByte, encodingFormat);
                return result;
            }

            return null;
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
        } catch (InvalidParameterSpecException e) {
            e.printStackTrace();
        } catch (InvalidAlgorithmParameterException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (BadPaddingException e) {
            e.printStackTrace();
        } catch (IllegalBlockSizeException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return null;
    }
}

效果展示

在这里插入图片描述

{"openId":"oFVAK4_iFtKuKDMpzEfAfjeI6ysQ","nickName":"菜逼玉","gender":1,"language":"zh_CN","city":"Chengdu","province":"Sichuan","country":"China","avatarUrl":"https://wx.qlogo.cn/mmopen/vi_32/Q0j4TwGTfTL94p6V7YgKUP2r9X4mLibwblyib3YAicRG54qAw2EEz0dO2ibMBLSnMqcm2CichAd3yZ36ZjBbMAdh7Wg/132","watermark":{"timestamp":1553434671,"appid":"wx08cbe6a7723b4059"}}

可以看到 我的微信的个人信息已经获得

四 小白踩坑记录

github上边有sdk可以用微信开发者联盟,但发现自己能力不足,只能用原生的方法。

大家在开发前一定要看小程序开发Api,不然会踩大坑。

新人第一篇博客 QQ:1056024860 敬候志同道合的同学跟我一起探讨微信开发

你可能感兴趣的:(微信开发,微信小程序,Java,Springboot)