1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        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進行關(guān)聯(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">授權(quán)登錄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() {
        ????// 頁面加載時使用用戶授權(quán)邏輯,彈出確認的框
        ????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

        設(shè)置app.json的pages

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

        測試

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

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

        ?

        清空緩存

        點擊授權(quán)登錄,并允許。

        授權(quán)登錄

        登錄成功

        ?

        登錄成功

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

        ?

        用戶信息入庫

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

        ?

        skey存儲本地



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

        ???

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



        感謝點贊支持下哈?

        瀏覽 56
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

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

        手機掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            激情午夜婷婷 | 抱着娇妻让粗大玩3p在线观看 | 五月激情四射丁香婷婷激情四射 | 欧美性精品 | 亚洲婷婷女色 | 好爽好紧宝贝别夹免费 | chinese国产精品 | 北条麻妃一区二区三区 | 豆花视频一区二区 | 国产精品久久久久永久免费 |