SpringBoot整合微信小程序登錄

該項目源碼地址:https://github.com/lastwhispers/springboot-integration-examples/tree/master/web/springboot-wx (其中包含SpringBoot和其他常用技術的整合,配套源碼以及筆記?;谧钚碌?SpringBoot2.1+,歡迎各位 Star)

1. 開發(fā)前準備

1.1 前置知識

  • java基礎
  • SpringBoot簡單基礎知識

1.2 環(huán)境參數(shù)

  • 開發(fā)工具:IDEA
  • 基礎環(huán)境:Maven+JDK8
  • 所用技術:SpringBoot、lombok、mybatisplus、微信小程序
  • SpringBoot版本:2.1.4

1.3 涉及知識點

  • 微信小程序登錄流程

2. 微信小程序登錄流程

微信小程序登錄流程涉及到三個角色:小程序、開發(fā)者服務器、微信服務器

三者交互步驟如下:

第一步:小程序通過wx.login()獲取code。
第二步:小程序通過wx.request()發(fā)送code到開發(fā)者服務器。
第三步:開發(fā)者服務器接收小程序發(fā)送的code,并攜帶appid、appsecret(這兩個需要到微信小程序后臺查看)、code發(fā)送到微信服務器。
第四步:微信服務器接收開發(fā)者服務器發(fā)送的appid、appsecret、code進行校驗。校驗通過后向開發(fā)者服務器發(fā)送session_key、openid。
第五步:開發(fā)者服務器自己生成一個skey(自定義登錄狀態(tài))與openid、session_key進行關聯(lián),并存到數(shù)據(jù)庫中(mysql、redis等)。
第六步:開發(fā)者服務器返回生成skey(自定義登錄狀態(tài))到小程序。
第七步:小程序存儲skey(自定義登錄狀態(tài))到本地。
第八步:小程序通過wx.request()發(fā)起業(yè)務請求到開發(fā)者服務器,同時攜帶skey(自定義登錄狀態(tài))。
第九步:開發(fā)者服務器接收小程序發(fā)送的skey(自定義登錄狀態(tài)),查詢skey在數(shù)據(jù)庫中是否有對應的openid、session_key。
第十步:開發(fā)者服務器返回業(yè)務數(shù)據(jù)到小程序

登錄流程時序如下:

登錄流程時序

本文實現(xiàn)了前七個步驟,因為微信小程序登錄的核心就是前七個步驟。

第一步:小程序通過wx.login()獲取code。
第二步:小程序通過wx.request()發(fā)送code到開發(fā)者服務器。
第三步:開發(fā)者服務器接收小程序發(fā)送的code,并攜帶appid、appsecret(這兩個需要到微信小程序后臺查看)、code發(fā)送到微信服務器。
第四步:微信服務器接收開發(fā)者服務器發(fā)送的appid、appsecret、code進行校驗。校驗通過后向開發(fā)者服務器發(fā)送session_key、openid。
第五步:開發(fā)者服務器自己生成一個skey(自定義登錄狀態(tài))與openid、session_key進行關聯(lián),并存到數(shù)據(jù)庫中(mysql、redis等)。
第六步:開發(fā)者服務器返回生成skey(自定義登錄狀態(tài))到小程序。
第七步:小程序存儲skey(自定義登錄狀態(tài))到本地。

本文介紹的流程

3. 開發(fā)者服務器

項目結構:

項目結構

3.1 初始配置

(1)pom.xml配置

<!-- http請求工具包依賴 -->
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.5.2</version>
        </dependency>

        <dependency>
            <groupId>org.bouncycastle</groupId>
            <artifactId>bcprov-jdk16</artifactId>
            <version>1.46</version>
        </dependency>

        <!--base64加密解密-->
        <!--shiro依賴和緩存-->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-core</artifactId>
            <version>1.4.0</version>
            <exclusions>
                <exclusion>
                    <artifactId>slf4j-api</artifactId>
                    <groupId>org.slf4j</groupId>
                </exclusion>
            </exclusions>
        </dependency>

        <!-- fastjson -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.47</version>
        </dependency>

        <!--簡化代碼的工具包-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <!--mybatis-plus的springboot支持-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.1.1</version>
        </dependency>
        <!--mysql驅動-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>

(2)application.properties

spring.application.name = lastwhisper-wxlogin
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/wxlogin?useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true&useSSL=false
spring.datasource.username=root
spring.datasource.password=root

3.2 小程序用戶表

創(chuàng)建一個用戶表存儲用戶的openid等數(shù)據(jù)。

CREATE TABLE `user`  (
  `open_id` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'open_id',
  `skey` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'skey',
  `create_time` timestamp(0) NULL DEFAULT CURRENT_TIMESTAMP COMMENT '創(chuàng)建時間',
  `last_visit_time` timestamp(0) NULL DEFAULT CURRENT_TIMESTAMP COMMENT '最后登錄時間',
  `session_key` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'session_key',
  `city` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '市',
  `province` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '省',
  `country` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '國',
  `avatar_url` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '頭像',
  `gender` tinyint(11) NULL DEFAULT NULL COMMENT '性別',
  `nick_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '網(wǎng)名',
  PRIMARY KEY (`open_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '微信用戶信息' ROW_FORMAT = Dynamic;

3.3 pojo

package cn.lastwhisper.springbootwx.pojo;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;

import java.util.Date;

/**
 * @author lastwhisper
 * @desc
 * @email gaojun56@163.com
 */
@Data
@TableName("user")
public class User {
    private static final long serialVersionUID = 1L;
    /**
     * open_id
     */
    @TableId(value = "open_id",type = IdType.INPUT)
    private String openId;
    /**
     * skey
     */
    private String skey;
    /**
     * 創(chuàng)建時間
     */
    @TableField("create_time")
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private Date createTime;
    /**
     * 最后登錄時間
     */
    @TableField("last_visit_time")
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private Date lastVisitTime;
    /**
     * session_key
     */
    @TableField("session_key")
    private String sessionKey;
    /**
     * 市
     */
    @TableField("city")
    private String city;
    /**
     * 省
     */
    @TableField("province")
    private String province;
    /**
     * 國
     */
    @TableField("country")
    private String country;
    /**
     * 頭像
     */
    @TableField("avatar_url")
    private String avatarUrl;
    /**
     * 性別
     */
    @TableField("gender")
    private Integer gender;
    /**
     * 網(wǎng)名
     */
    @TableField("nick_name")
    private String nickName;

}

3.4 common

封裝一些工具類

(1)GlobalResult

package cn.lastwhisper.springbootwx.common;

/**
 * @Description: 自定義響應數(shù)據(jù)結構
 *              這個類是提供給門戶,ios,安卓,微信商城用的
 *              門戶接受此類數(shù)據(jù)后需要使用本類的方法轉換成對于的數(shù)據(jù)類型格式(類,或者list)
 *              其他自行處理
 *              200:表示成功
 *              500:表示錯誤,錯誤信息在msg字段中
 *              501:bean驗證錯誤,不管多少個錯誤都以map形式返回
 *              502:攔截器攔截到用戶token出錯
 *              555:異常拋出信息
 */
public class GlobalResult {

    // 響應業(yè)務狀態(tài)
    private Integer status;

    // 響應消息
    private String msg;

    // 響應中的數(shù)據(jù)
    private Object data;
    
    private String ok;  // 不使用

    public static GlobalResult build(Integer status, String msg, Object data) {
        return new GlobalResult(status, msg, data);
    }

    public static GlobalResult ok(Object data) {
        return new GlobalResult(data);
    }

    public static GlobalResult ok() {
        return new GlobalResult(null);
    }
    
    public static GlobalResult errorMsg(String msg) {
        return new GlobalResult(500, msg, null);
    }
    
    public static GlobalResult errorMap(Object data) {
        return new GlobalResult(501, "error", data);
    }
    
    public static GlobalResult errorTokenMsg(String msg) {
        return new GlobalResult(502, msg, null);
    }
    
    public static GlobalResult errorException(String msg) {
        return new GlobalResult(555, msg, null);
    }

    public GlobalResult() {

    }

    public GlobalResult(Integer status, String msg, Object data) {
        this.status = status;
        this.msg = msg;
        this.data = data;
    }

    public GlobalResult(Object data) {
        this.status = 200;
        this.msg = "OK";
        this.data = data;
    }

    public Boolean isOK() {
        return this.status == 200;
    }

    public Integer getStatus() {
        return status;
    }

    public void setStatus(Integer status) {
        this.status = status;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }

    public String getOk() {
        return ok;
    }

    public void setOk(String ok) {
        this.ok = ok;
    }

}

(2)HttpClientUtil

package cn.lastwhisper.springbootwx.common;

import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class HttpClientUtil {

    public static String doGet(String url, Map<String, String> param) {

        // 創(chuàng)建Httpclient對象
        CloseableHttpClient httpclient = HttpClients.createDefault();

        String resultString = "";
        CloseableHttpResponse response = null;
        try {
            // 創(chuàng)建uri
            URIBuilder builder = new URIBuilder(url);
            if (param != null) {
                for (String key : param.keySet()) {
                    builder.addParameter(key, param.get(key));
                }
            }
            URI uri = builder.build();

            // 創(chuàng)建http GET請求
            HttpGet httpGet = new HttpGet(uri);

            // 執(zhí)行請求
            response = httpclient.execute(httpGet);
            // 判斷返回狀態(tài)是否為200
            if (response.getStatusLine().getStatusCode() == 200) {
                resultString = EntityUtils.toString(response.getEntity(), "UTF-8");
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (response != null) {
                    response.close();
                }
                httpclient.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return resultString;
    }

    public static String doGet(String url) {
        return doGet(url, null);
    }

    public static String doPost(String url, Map<String, String> param) {
        // 創(chuàng)建Httpclient對象
        CloseableHttpClient httpClient = HttpClients.createDefault();
        CloseableHttpResponse response = null;
        String resultString = "";
        try {
            // 創(chuàng)建Http Post請求
            HttpPost httpPost = new HttpPost(url);
            // 創(chuàng)建參數(shù)列表
            if (param != null) {
                List<NameValuePair> paramList = new ArrayList<>();
                for (String key : param.keySet()) {
                    paramList.add(new BasicNameValuePair(key, param.get(key)));
                }
                // 模擬表單
                UrlEncodedFormEntity entity = new UrlEncodedFormEntity(paramList);
                httpPost.setEntity(entity);
            }
            // 執(zhí)行http請求
            response = httpClient.execute(httpPost);
            resultString = EntityUtils.toString(response.getEntity(), "utf-8");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                response.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return resultString;
    }

    public static String doPost(String url) {
        return doPost(url, null);
    }

    public static String doPostJson(String url, String json) {
        // 創(chuàng)建Httpclient對象
        CloseableHttpClient httpClient = HttpClients.createDefault();
        CloseableHttpResponse response = null;
        String resultString = "";
        try {
            // 創(chuàng)建Http Post請求
            HttpPost httpPost = new HttpPost(url);
            // 創(chuàng)建請求內容
            StringEntity entity = new StringEntity(json, ContentType.APPLICATION_JSON);
            httpPost.setEntity(entity);
            // 執(zhí)行http請求
            response = httpClient.execute(httpPost);
            resultString = EntityUtils.toString(response.getEntity(), "utf-8");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                response.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return resultString;
    }
}

(3)WechatUtil

package cn.lastwhisper.springbootwx.common;/**
 * Create by eval on 2019/3/20
 */

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.shiro.codec.Base64;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.AlgorithmParameters;
import java.security.Security;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

/**
 * @ClassName WechatUtil
 * @Description TODO
 * @Author eval
 * @Date 9:44 2019/3/20
 * @Version 1.0
 */
public class WechatUtil {
    public static JSONObject getSessionKeyOrOpenId(String code) {
        String requestUrl = "https://api.weixin.qq.com/sns/jscode2session";
        Map<String, String> requestUrlParam = new HashMap<>();
        // https://mp.weixin.qq.com/wxopen/devprofile?action=get_profile&token=164113089&lang=zh_CN
        //小程序appId
        requestUrlParam.put("appid", "小程序appId");
        //小程序secret
        requestUrlParam.put("secret", "小程序secret");
        //小程序端返回的code
        requestUrlParam.put("js_code", code);
        //默認參數(shù)
        requestUrlParam.put("grant_type", "authorization_code");
        //發(fā)送post請求讀取調用微信接口獲取openid用戶唯一標識
        JSONObject jsonObject = JSON.parseObject(HttpClientUtil.doPost(requestUrl, requestUrlParam));
        return jsonObject;
    }

    public static JSONObject getUserInfo(String encryptedData, String sessionKey, String iv) {
        // 被加密的數(shù)據(jù)
        byte[] dataByte = Base64.decode(encryptedData);
        // 加密秘鑰
        byte[] keyByte = Base64.decode(sessionKey);
        // 偏移量
        byte[] ivByte = Base64.decode(iv);
        try {
            // 如果密鑰不足16位,那么就補足.  這個if 中的內容很重要
            int base = 16;
            if (keyByte.length % base != 0) {
                int groups = keyByte.length / base + (keyByte.length % base != 0 ? 1 : 0);
                byte[] temp = new byte[groups * base];
                Arrays.fill(temp, (byte) 0);
                System.arraycopy(keyByte, 0, temp, 0, keyByte.length);
                keyByte = temp;
            }
            // 初始化
            Security.addProvider(new BouncyCastleProvider());
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding", "BC");
            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, "UTF-8");
                return JSON.parseObject(result);
            }
        } catch (Exception e) {
        }
        return null;
    }
}

3.5 mapper

package cn.lastwhisper.springbootwx.mapper;

import cn.lastwhisper.springbootwx.pojo.User;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;

/**
 * @desc
 * 
 * @author lastwhisper
 * @email gaojun56@163.com
 */
public interface UserMapper extends BaseMapper<User> {
}

配置SpringBoot掃描mapper

package cn.lastwhisper.springbootwx;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@MapperScan("cn.lastwhisper.springbootwx.mapper") //設置mapper接口的掃描包
@SpringBootApplication
public class SpringbootwxApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringbootwxApplication.class, args);
    }

}

3.6 controller

用于接收用戶請求,校驗簽名,并生成skey,存儲skey、openid等數(shù)據(jù)

package cn.lastwhisper.springbootwx.controller;

import cn.lastwhisper.springbootwx.common.GlobalResult;
import cn.lastwhisper.springbootwx.mapper.UserMapper;
import cn.lastwhisper.springbootwx.pojo.User;
import cn.lastwhisper.springbootwx.common.WechatUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.Date;
import java.util.UUID;

/**
 * @author lastwhisper
 * @desc
 * @email gaojun56@163.com
 */
@Controller
public class UserController {

    @Autowired
    private UserMapper userMapper;

    /**
     * 微信用戶登錄詳情
     */
    @PostMapping("wx/login")
    @ResponseBody
    public GlobalResult user_login(@RequestParam(value = "code", required = false) String code,
                                   @RequestParam(value = "rawData", required = false) String rawData,
                                   @RequestParam(value = "signature", required = false) String signature,
                                   @RequestParam(value = "encrypteData", required = false) String encrypteData,
                                   @RequestParam(value = "iv", required = false) String iv) {
        // 用戶非敏感信息:rawData
        // 簽名:signature
        JSONObject rawDataJson = JSON.parseObject(rawData);
        // 1.接收小程序發(fā)送的code
        // 2.開發(fā)者服務器 登錄憑證校驗接口 appi + appsecret + code
        JSONObject SessionKeyOpenId = WechatUtil.getSessionKeyOrOpenId(code);
        // 3.接收微信接口服務 獲取返回的參數(shù)
        String openid = SessionKeyOpenId.getString("openid");
        String sessionKey = SessionKeyOpenId.getString("session_key");

        // 4.校驗簽名 小程序發(fā)送的簽名signature與服務器端生成的簽名signature2 = sha1(rawData + sessionKey)
        String signature2 = DigestUtils.sha1Hex(rawData + sessionKey);
        if (!signature.equals(signature2)) {
            return GlobalResult.build(500, "簽名校驗失敗", null);
        }
        // 5.根據(jù)返回的User實體類,判斷用戶是否是新用戶,是的話,將用戶信息存到數(shù)據(jù)庫;不是的話,更新最新登錄時間
        User user = this.userMapper.selectById(openid);
        // uuid生成唯一key,用于維護微信小程序用戶與服務端的會話
        String skey = UUID.randomUUID().toString();
        if (user == null) {
            // 用戶信息入庫
            String nickName = rawDataJson.getString("nickName");
            String avatarUrl = rawDataJson.getString("avatarUrl");
            String gender = rawDataJson.getString("gender");
            String city = rawDataJson.getString("city");
            String country = rawDataJson.getString("country");
            String province = rawDataJson.getString("province");

            user = new User();
            user.setOpenId(openid);
            user.setSkey(skey);
            user.setCreateTime(new Date());
            user.setLastVisitTime(new Date());
            user.setSessionKey(sessionKey);
            user.setCity(city);
            user.setProvince(province);
            user.setCountry(country);
            user.setAvatarUrl(avatarUrl);
            user.setGender(Integer.parseInt(gender));
            user.setNickName(nickName);

            this.userMapper.insert(user);
        } else {
            // 已存在,更新用戶登錄時間
            user.setLastVisitTime(new Date());
            // 重新設置會話skey
            user.setSkey(skey);
            this.userMapper.updateById(user);
        }
        //encrypteData比rowData多了appid和openid
        //JSONObject userInfo = WechatUtil.getUserInfo(encrypteData, sessionKey, iv);
        //6. 把新的skey返回給小程序
        GlobalResult result = GlobalResult.build(200, null, skey);
        return result;
    }
}

4. 微信小程序

項目結構:

項目結構

4.1 初始配置

初始配置

4.2 me.wxml

<view class="container">
  <!-- 登錄組件 https://developers.weixin.qq.com/miniprogram/dev/api/wx.getUserInfo.html -->  
  <button wx:if="{{!hasUserInfo}}" open-type="getUserInfo" bind:getuserinfo="onGetUserInfo">授權登錄</button>
  <!-- 登錄后使用open-data -->
  <view class="avatar-container avatar-position">
      <image src="{{userInfo.avatarUrl}}" wx:if="{{hasUserInfo}}" class="avatar" />
      <open-data wx:if="{{hasUserInfo}}" type="userNickName"></open-data>
  </view>
</view>

4.3 me.wxss

4.4 me.json

{
  
}

4.5 me.js

// pages/me/me.js
Page({

  /**
   * 頁面的初始數(shù)據(jù)
   */
  data: {
    hasUserInfo: false,
    userInfo: null
  },

  onLoad: function() {
    // 頁面加載時使用用戶授權邏輯,彈出確認的框  
    this.userAuthorized()
  },
  
  userAuthorized() {
    wx.getSetting({
      success: data => {
        if (data.authSetting['scope.userInfo']) {
          wx.getUserInfo({
            success: data => {
              this.setData({
                hasUserInfo: true,
                userInfo: data.userInfo
              })
            }
          })
        } else {
          this.setData({
            hasUserInfo: false
          })
        }
      }
    })
  },

  onGetUserInfo(e) {
    const userInfo = e.detail.userInfo
    if (userInfo) {
      // 1. 小程序通過wx.login()獲取code
      wx.login({
        success: function(login_res) {
          //獲取用戶信息
          wx.getUserInfo({
            success: function(info_res) {
              // 2. 小程序通過wx.request()發(fā)送code到開發(fā)者服務器
              wx.request({
                url: 'http://localhost:8080/wx/login',
                method: 'POST',
                header: {
                  'content-type': 'application/x-www-form-urlencoded'
                },
                data: {
                  code: login_res.code, //臨時登錄憑證
                  rawData: info_res.rawData, //用戶非敏感信息
                  signature: info_res.signature, //簽名
                  encrypteData: info_res.encryptedData, //用戶敏感信息
                  iv: info_res.iv //解密算法的向量
                },
                success: function(res) {
                  if (res.data.status == 200) {
                    // 7.小程序存儲skey(自定義登錄狀態(tài))到本地
                    wx.setStorageSync('userInfo', userInfo);
                    wx.setStorageSync('skey', res.data.data);
                  } else{
                    console.log('服務器異常');
                  }
                },
                fail: function(error) {
                  //調用服務端登錄接口失敗
                  console.log(error);
                }
              })
            }
          })
        }
      })
      this.setData({
        hasUserInfo: true,
        userInfo: userInfo
      })
    }
  }

})

4.6 app.json

設置app.json的pages

{
  "pages":[
    "pages/me/me"
  ],
  "window":{
    "backgroundTextStyle":"light",
    "navigationBarBackgroundColor": "#fff",
    "navigationBarTitleText": "WeChat",
    "navigationBarTextStyle":"black"
  },
  "debug":true
}

5. 測試

啟動開發(fā)者服務器,啟動SpringBoot的main方法。

打開微信小程序開發(fā)者工具

清空緩存

點擊授權登錄,并允許。

授權登錄

登錄成功

登錄成功

查看數(shù)據(jù)庫,openid、skey以及用戶信息等存入了數(shù)據(jù)庫。

用戶信息入庫

同時微信小程序將skey等存儲到本地,每次發(fā)起請求時都可以攜帶上。

skey存儲本地
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • 火車晚點15分,早上到揚州已經7:45分了,這時先生也上班了,正好也累了,回來沖了涼就準備平臺轉播課件,轉播結束后...
    卉卉堯堯閱讀 355評論 0 0
  • 我喜歡收集車票,電影票還有類似于這樣有紀念意義的小東西,總覺得有一天我會好好寫篇關于它們的成長故事,某個妞每次整...
    樟子_e953閱讀 353評論 0 0
  • 感恩父母養(yǎng)育之恩愿母親身體健康衣食無憂智慧增長!感恩母親身體健康給我膝前盡孝的機會!感恩母親無條件的愛!感恩嫂嫂的...
    T上善若水閱讀 204評論 0 0
  • 閱讀文章:《你是不是在混日子?看這一點就夠了》 文章開頭用問題的方式展開:“請問你,什么對職場人最高的評價? 這么...
    向陽i閱讀 330評論 0 0

友情鏈接更多精彩內容