<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          SpringBoot整合微信小程序登錄

          共 7663字,需瀏覽 16分鐘

           ·

          2020-09-01 10:50

          點擊上方藍色字體,選擇“標星公眾號”

          優(yōu)質(zhì)文章,第一時間送達

          ? 作者?|??鄧維-java

          來源 |? urlify.cn/aEB3Qj ??

          66套java從入門到精通實戰(zhàn)課程分享?

          微信小程序登錄流程

          微信小程序登錄流程涉及到三個角色:小程序、開發(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ù)到小程序

          yml:

          ???<dependency>
          ????????????<groupId>cn.hutoolgroupId>
          ????????????<artifactId>hutool-allartifactId>
          ????????????<version>5.4.0version>
          ?????dependency>

          ????????<dependency>
          ????????????<groupId>org.projectlombokgroupId>
          ????????????<artifactId>lombokartifactId>
          ????????????<optional>trueoptional>
          ????????dependency>
          <dependency>????<groupId>com.baomidougroupId>????<artifactId>mybatis-plus-boot-starterartifactId>????<version>3.3.2version>dependency>


          wx返回的用戶信息:

          /**
          ?* @Author?dw
          ?* @ClassName?WeChatUserInfo
          ?* @Description?微信用戶信息
          ?* @Date?2020/8/28 14:14
          ?* @Version?1.0
          ?*/

          @Data
          public?class?WeChatUserInfo?{
          ????/**
          ?????* 微信返回的code
          ?????*/

          ????private?String code;
          ????/**
          ?????* 非敏感的用戶信息
          ?????*/

          ????private?String rawData;
          ????/**
          ?????* 簽名信息
          ?????*/

          ????private?String signature;
          ????/**
          ?????* 加密的數(shù)據(jù)
          ?????*/

          ????private?String encrypteData;
          ????/**
          ?????* 加密密鑰
          ?????*/

          ????private?String iv;

          }


          WeChatUtil工具:
          /**
          ?* @Author dw
          ?* @ClassName WeChatUtil
          ?* @Description
          ?* @Date 2020/8/28 10:56
          ?* @Version 1.0
          ?*/

          public?class?WeChatUtil?{

          ????public?static?JSONObject getSessionKeyOrOpenId(String code) {
          ????????String requestUrl = "https://api.weixin.qq.com/sns/jscode2session";
          ????????HashMap requestUrlParam = new?HashMap<>();
          ????????//小程序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請求讀取調(diào)用微信接口獲取openid用戶唯一標識
          ????????String result = HttpUtil.get(requestUrl, requestUrlParam);
          ????????JSONObject jsonObject = JSONUtil.parseObj(result);
          ????????return?jsonObject;
          ????}

          ????public?static?JSONObject getUserInfo(String encryptedData, String sessionKey, String iv) throws Base64DecodingException {
          ????????// 被加密的數(shù)據(jù)
          ????????byte[] dataByte = Base64.decode(encryptedData);
          ????????// 加密秘鑰
          ????????byte[] keyByte = Base64.decode(sessionKey);
          ????????// 偏移量
          ????????byte[] ivByte = Base64.decode(iv);
          ????????try?{
          ????????????// 如果密鑰不足16位,那么就補足. 這個if 中的內(nèi)容很重要
          ????????????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?JSONUtil.parseObj(result);
          ????????????}
          ????????} catch?(Exception e) {
          ????????}
          ????????return?null;
          ????}


          登錄controller:

          /**
          ?* @Author dw
          ?* @ClassName WeChatUserLoginController
          ?* @Description
          ?* @Date 2020/8/28 14:12
          ?* @Version 1.0
          ?*/

          @RestController
          public?class?WeChatUserLoginController {

          ????@Resource
          ????private?IUserService userService;

          ????/**
          ?????* 微信用戶登錄詳情
          ?????*/

          ????@PostMapping("wx/login")
          ????public?ResultInfo user_login(@RequestBody?WeChatUserInfo weChatUserInfo) throws Base64DecodingException {
          ????????// 2.開發(fā)者服務器 登錄憑證校驗接口 appId + appSecret + 接收小程序發(fā)送的code
          ????????JSONObject SessionKeyOpenId = WeChatUtil.getSessionKeyOrOpenId(weChatUserInfo.getCode());
          ????????// 3.接收微信接口服務 獲取返回的參數(shù)
          ????????String?openid = SessionKeyOpenId.get("openid", String.class);
          ????????String?sessionKey = SessionKeyOpenId.get("session_key", String.class);
          ????????// 用戶非敏感信息:rawData
          ????????// 簽名:signature
          ????????JSONObject rawDataJson = JSONUtil.parseObj(weChatUserInfo.getRawData());
          ????????// 4.校驗簽名 小程序發(fā)送的簽名signature與服務器端生成的簽名signature2 = sha1(rawData + sessionKey)
          ????????String?signature2 = DigestUtils.sha1Hex(weChatUserInfo.getRawData() + sessionKey);
          ????????if?(!weChatUserInfo.getSignature().equals(signature2)) {
          ????????????return?ResultInfo.error( "簽名校驗失敗");
          ????????}
          ????????//encrypteData比rowData多了appid和openid
          ????????JSONObject userInfo = WeChatUtil.getUserInfo(weChatUserInfo.getEncrypteData(),
          ????????????????sessionKey, weChatUserInfo.getIv());
          ????????// 5.根據(jù)返回的User實體類,判斷用戶是否是新用戶,是的話,將用戶信息存到數(shù)據(jù)庫;不是的話,更新最新登錄時間
          ????????QueryWrapper userQueryWrapper = new?QueryWrapper<>();
          ????????userQueryWrapper.lambda().eq(User::getLoginName, openid);
          ????????int userCount = userService.count(userQueryWrapper);
          ????????// uuid生成唯一key,用于維護微信小程序用戶與服務端的會話(或者生成Token)
          ????????String?skey = UUID.randomUUID().toString();
          ????????if?(userCount <= 0) {
          ????????????// 用戶信息入庫
          ????????????String?nickName = rawDataJson.get("nickName",String.class);
          ????????????String?avatarUrl = rawDataJson.get("avatarUrl",String.class);
          ????????????String?gender = rawDataJson.get("gender",String.class);
          ????????????String?city = rawDataJson.get("city",String.class);
          ????????????String?country = rawDataJson.get("country",String.class);
          ????????????String?province = rawDataJson.get("province",String.class);
          ???????????// 新增用戶到數(shù)據(jù)庫
          ????????} else?{
          ????????????// 已存在,更新用戶登錄時間

          ????????}
          ????????//6. 把新的skey返回給小程序
          ????????return?ResultInfo.success();
          ????}


          }

          全局返回結(jié)果:

          public?class?ResultInfo?{
          ????/**
          ?????* 響應代碼
          ?????*/

          ????private?String code;

          ????/**
          ?????* 響應消息
          ?????*/

          ????private?String message;

          ????/**
          ?????* 響應結(jié)果
          ?????*/

          ????private?Object result;

          ????public?ResultInfo() {
          ????}

          ????public?ResultInfo(BaseErrorInfoInterface errorInfo) {
          ????????this.code = errorInfo.getResultCode();
          ????????this.message = errorInfo.getResultMsg();
          ????}

          ????public?String getCode() {
          ????????return?code;
          ????}

          ????public?void?setCode(String code) {
          ????????this.code = code;
          ????}

          ????public?String getMessage() {
          ????????return?message;
          ????}

          ????public?void?setMessage(String message) {
          ????????this.message = message;
          ????}

          ????public?Object getResult() {
          ????????return?result;
          ????}

          ????public?void?setResult(Object result) {
          ????????this.result = result;
          ????}

          ????/**
          ?????* 成功
          ?????*
          ?????* @return
          ?????*/

          ????public?static?ResultInfo success() {
          ????????return?success(null);
          ????}

          ????/**
          ?????* 成功
          ?????* @param data
          ?????* @return
          ?????*/

          ????public?static?ResultInfo success(Object data) {
          ????????ResultInfo rb = new?ResultInfo();
          ????????rb.setCode(CommonEnum.SUCCESS.getResultCode());
          ????????rb.setMessage(CommonEnum.SUCCESS.getResultMsg());
          ????????rb.setResult(data);
          ????????return?rb;
          ????}

          ????/**
          ?????* 失敗
          ?????*/

          ????public?static?ResultInfo error(BaseErrorInfoInterface errorInfo) {
          ????????ResultInfo rb = new?ResultInfo();
          ????????rb.setCode(errorInfo.getResultCode());
          ????????rb.setMessage(errorInfo.getResultMsg());
          ????????rb.setResult(null);
          ????????return?rb;
          ????}

          ????/**
          ?????* 失敗
          ?????*/

          ????public?static?ResultInfo error(String code, String message) {
          ????????ResultInfo rb = new?ResultInfo();
          ????????rb.setCode(code);
          ????????rb.setMessage(message);
          ????????rb.setResult(null);
          ????????return?rb;
          ????}

          ????/**
          ?????* 失敗
          ?????*/

          ????public?static?ResultInfo error(String message) {
          ????????ResultInfo rb = new?ResultInfo();
          ????????rb.setCode("-1");
          ????????rb.setMessage(message);
          ????????rb.setResult(null);
          ????????return?rb;
          ????}}


          ?微信小程序

          項目結(jié)構(gòu):

          項目結(jié)構(gòu)

          1 初始配置

          ?

          初始配置

          2 me.wxml

          <view?class="container">
          ????
          ??<button?wx:if="{{!hasUserInfo}}"?open-type="getUserInfo"?bind:getuserinfo="onGetUserInfo">授權登錄button>
          ??
          ??<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>

          3 me.wxss

          4 me.json

          {
          ??
          }

          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/json'
          ????????????????},
          ????????????????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) {
          ??????????????????//調(diào)用服務端登錄接口失敗
          ??????????????????console.log(error);
          ????????????????}
          ??????????????})
          ????????????}
          ??????????})
          ????????}
          ??????})
          ??????this.setData({
          ????????hasUserInfo: true,
          ????????userInfo: userInfo
          ??????})
          ????}
          ??}

          })

          6 app.json

          設置app.json的pages

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

          測試

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

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

          ?

          清空緩存

          點擊授權登錄,并允許。

          授權登錄

          登錄成功

          ?

          登錄成功

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

          ?

          用戶信息入庫

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

          ?

          skey存儲本地



          粉絲福利:108本java從入門到大神精選電子書領取

          ???

          ?長按上方鋒哥微信二維碼?2 秒
          備注「1234」即可獲取資料以及
          可以進入java1234官方微信群



          感謝點贊支持下哈?

          瀏覽 56
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  欧美无砖砖区免费 | 日韩嫩穴| 九九AV| 看黄色大片 | 97小视频 |