java springboot 微信小程序登录,获取获取手机号,获取unionId和解密用户信息

前端代码

前端使用的uniapp,我这边只写了个示例

<template>
  <view class="content">
    <image class="logo" src="/static/logo.png"></image>
    <view class="text-area">
      <text class="title">{{ title }}</text>
	  <button type="default" @tap="appLoginWx" >微信登录</button>
	  <button open-type="getPhoneNumber"  @getphonenumber="getPhoneNumber">获取手机号</button>
    </view>
  </view>
</template>

<script>
export default {
  data() {
    return {
      title: "Hello",
    };
  },
  onLoad() {
    // todo 微信小程序登录授权
    uni.login({
      provider: "weixin",
      success: (result) => {
        console.log("🚀🚀🚀 ~ onLoad ~ result:", result);
		
      },

      fail: (error) => {},
    });
  },
  methods: {
	  appLoginWx(){
	      // 获取用户信息
	      // 注意 getUserProfile 不支持在事件中使用异步操作
	      // 否则会触发错误:{errMsg: "getUserProfile:fail can only be invoked by user TAP gesture."}
	      uni.getUserInfo({  
	          lang: 'zh_CN',
	          desc:'获取用户信息',
	          success: userInfo=> {
	              console.log(userInfo,'userInfo');
	              uni.login({
	                  provider: 'weixin',
	                  success: loginInfo=> {
	                      console.log(loginInfo,'loginInfo');     
	                  }
	              });
	           },
	          fail:err=>{
	              console.log(err,'err')
	          }
	      });
	  },
    //
	getPhoneNumber(e) {
		console.log('phoneCode:'+e.detail.code)
	},
  },
};
</script>

<style>
.content {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}

.logo {
  height: 200rpx;
  width: 200rpx;
  margin-top: 200rpx;
  margin-left: auto;
  margin-right: auto;
  margin-bottom: 50rpx;
}

.text-area {
  display: flex;
  justify-content: center;
}

.title {
  font-size: 36rpx;
  color: #8f8f94;
}
</style>

后端代码以及配置

微信相关配置

wx:
  appId: wx199139f6xxxxx
  appSecret: 7b9ac2dcbbfa930xxxx

微信相关service
相关的Result,RedisUtil,YlCheckUser使用自己的

package com.applets.manager.core.service;

import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.applets.manager.core.model.Result;
import com.applets.manager.core.model.dto.WxPhoneInfoRes;
import com.applets.manager.core.model.dto.WxUserInfo;
import com.applets.manager.core.model.entity.YlCheckUser;
import com.applets.manager.core.util.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;

import org.springframework.beans.factory.annotation.Value;

import org.springframework.stereotype.Service;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * 微信能力
 * @author zr 2024/4/16
 */
@Slf4j
@Service
public class WxService {
    @Value("${wx.appId}")
    private String appId;

    @Value("${wx.appSecret}")
    private String appSecret;

    private final String ACCESS_TOKEN_KEY = "applets:accessToken";//redis使用
    private final String LOGIN = "https://api.weixin.qq.com/sns/jscode2session";
    private final String GET_ACCESS_TOKEN = "https://api.weixin.qq.com/cgi-bin/token";
    private final String GET_USER_PHONE_NUMBER = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=%s";

    /**
     * 微信用户登录
     * @param code
     * @return
     */
    public Result<YlCheckUser> wxLogin(String code) {
        HashMap<String, Object> parameter = new HashMap<>();
        parameter.put("appid", appId);
        parameter.put("secret", appSecret);
        parameter.put("js_code", code);
        parameter.put("grant_type", "authorization_code");
        HttpResponse response = httpGet(LOGIN, null, parameter);
        String res = response.body();
        JSONObject jsonObject = JSON.parseObject(res);
        Integer errcode = jsonObject.getInteger("errcode");
        if (ObjectUtils.isEmpty(errcode)) {
            String sessionKey = jsonObject.getString("session_key");
            String openid = jsonObject.getString("openid");
            YlCheckUser checkUser = new YlCheckUser();
            checkUser.setSessionKey(sessionKey);
            checkUser.setOpenId(openid);
            return Result.success(checkUser);
        } else {
            return Result.failure("微信错误:" + jsonObject.getString("errmsg"));
        }
    }

    /**
     * 获取用户手机号信息
     * @param code
     * @return
     */

    public Result getUserPhoneNumber(String code) {
        HashMap<String, Object> parameter = new HashMap<>();
        parameter.put("code", code);
        String url = String.format(GET_USER_PHONE_NUMBER, getAccessToken().getResult());
        String res = httpPost(url, JSON.toJSONString(parameter));
        JSONObject jsonObject = JSON.parseObject(res);
        Integer errcode = jsonObject.getInteger("errcode");
        if (errcode ==0) {
            WxPhoneInfoRes wxPhoneInfoRes = jsonObject.getObject("phone_info", WxPhoneInfoRes.class);
            YlCheckUser checkUser = new YlCheckUser();
            checkUser.setPhone(wxPhoneInfoRes.getPhoneNumber());
            return Result.success(checkUser);
        } else {
            RedisUtil.KeyOps.delete(ACCESS_TOKEN_KEY);
            getAccessToken();
            return Result.failure("微信错误:" + jsonObject.getString("errmsg"));
        }
    }




    /**
     * 更新或刷新accessToken
     * @return
     */
    public Result<String> getAccessToken() {
        String accessToken = RedisUtil.StringOps.get(ACCESS_TOKEN_KEY);
        if (StringUtils.isNotEmpty(accessToken)){
            return Result.success(accessToken);
        }
        HashMap<String, Object> parameter = new HashMap<>();
        parameter.put("appid", appId);
        parameter.put("secret", appSecret);
        parameter.put("grant_type", "client_credential");
        HttpResponse response = httpGet(GET_ACCESS_TOKEN, null, parameter);
        String res = response.body();
        JSONObject jsonObject = JSON.parseObject(res);
        Integer errcode = jsonObject.getInteger("errcode");
        if (ObjectUtils.isEmpty(errcode)) {
            accessToken = jsonObject.getString("access_token");
            Integer expires = jsonObject.getInteger("expires_in");
            //微信默认过期时间7200s,即2h,提前200s
            RedisUtil.StringOps.setEx(ACCESS_TOKEN_KEY, accessToken, expires-200, TimeUnit.SECONDS);
            return Result.success(accessToken);
        } else {
            return Result.failure("微信错误:" + jsonObject.getString("errmsg"));
        }
    }

    public Result<YlCheckUser> getUserInfo(String encryptedData, String sessionKey, String iv){

        if (sessionKey.length() != 24) {
            return Result.failure("sessionKey长度错误");
        }
        byte[] aesKey = java.util.Base64.getDecoder().decode(sessionKey);

        if (iv.length() != 24) {
            return Result.failure("iv长度错误");
        }
        byte[] aesIV = java.util.Base64.getDecoder().decode(iv);
        byte[] aesCipher = java.util.Base64.getDecoder().decode(encryptedData);

        try {
            Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
            SecretKeySpec keySpec = new SecretKeySpec(aesKey, "AES");
            IvParameterSpec ivSpec = new IvParameterSpec(aesIV);
            cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
            byte[] resultBytes = cipher.doFinal(aesCipher);
            String result = new String(resultBytes, "UTF-8");

            JSONObject dataObj = JSONObject.parseObject(result);
            if (!appId.equals(dataObj.getJSONObject("watermark").getString("appid"))) {
                return null;
            }
            WxUserInfo wxUserInfo = dataObj.toJavaObject(WxUserInfo.class);

            YlCheckUser checkUser = new YlCheckUser();
            checkUser.setUnionId(wxUserInfo.getUnionId());
            checkUser.setOpenId(wxUserInfo.getOpenId());
//            return ylCheckUserService.saveUnionInfo(checkUser);
            return Result.success(checkUser);
        } catch (Exception e) {
            e.printStackTrace();
            return Result.failure("解密失败:{}"+e.getMessage());
        }
    }


    private HttpResponse httpGet(String url, Map<String, String> headers, Map<String, Object> parameter) {
        HttpRequest httpRequest = HttpUtil.createGet(url).form(parameter).addHeaders(headers);
        HttpResponse response = httpRequest.execute();
        log.info("Url: "+httpRequest.getUrl());
        log.info("head: "+JSON.toJSONString(httpRequest.headers()));
        log.info("parame: "+JSON.toJSONString(httpRequest.form()));
        log.info("res: "+response.body());
        return response;
    }

    private String httpPost(String url,String body) {
        String res = HttpUtil.post(url, body);
        log.info("Url: "+url);
        log.info("body: "+body);
        log.info("res: "+res);
        return res;
    }
}

微信相关controller

package com.applets.manager.api.controller.estimate;

import com.applets.manager.core.model.Result;
import com.applets.manager.core.model.entity.YlCheckUser;
import com.applets.manager.core.service.WxService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author zr 2024/4/15
 */
@Api(tags = "微信")
@RestController("/wx")
@Slf4j
public class WxController {
    @Autowired
    private WxService wxService;
    @GetMapping("/wxLogin")
    @ApiOperation(value = "微信登录")
    public Result<YlCheckUser> wxLogin(@RequestParam("code") String code) {

        try {
            return wxService.wxLogin(code);
        } catch (Exception e) {
            log.info(e.getMessage());
            return Result.failure(e.getMessage());
        }
    }

    @GetMapping("/getUserPhoneNumber")
    @ApiOperation(value = "获取用户电话信息")
    public Result<YlCheckUser> getUserPhoneNumber(@RequestParam("code") String code) {
        try {
            return wxService.getUserPhoneNumber(code);
        } catch (Exception e) {
            log.info(e.getMessage());
            return Result.failure(e.getMessage());
        }
    }

    @GetMapping("/getUserInfo")
    @ApiOperation(value = "获取用户信息")
    public Result<YlCheckUser> getUserInfo(@RequestParam("encryptedData") String encryptedData,
                                           @RequestParam("iv") String iv,
                                           @RequestParam("sessionKey") String sessionKey) {
        try {
            return wxService.getUserInfo(encryptedData,sessionKey,iv);
        } catch (Exception e) {
            log.info(e.getMessage());
            return Result.failure(e.getMessage());
        }
    }
}

微信返回用户信息对象

package com.applets.manager.core.model.dto;

import lombok.Data;

/**
 * @author zr 2024/4/23
 */
@Data
public class WxUserInfo {
    private String openId;
    private String nickName;
    private int gender;
    private String city;
    private String province;
    private String country;
    private String avatarUrl;
    private String unionId;
    private Watermark watermark;

    @Data
    public static class Watermark {
        private String appid;
        private long timestamp;
    }
}

测试

微信小程序登录

  1. 每次进入小程序后会自动小程序登录获取小程序授权码(开发者工具中即重新编译)

uni.login后会拿到小程序授权码每个码只能用一次
image.png

  1. 拿到授权码调用/wx/wxLogin接口,可以拿到openId和sessionKey

image.png

微信获取手机号

  1. 点击获取手机号,同意后获取到phoneCode

image.png

  1. 拿到授权码调用/wx/getUserPhoneNumber接口,可以拿到phone

image.png

获取用户信息和unionId

  1. 点击微信登录获取到用户信息(这里微信登录按钮文字写错了,应该是获取用户信息按钮)

image.png

  1. 拿到iv和encryptedData和3.1步骤得到的sessionKey调用/wx/getUserInfo接口

image.png

  1. 用户信息解密后可以拿到以下数据,可以自行封装

image.png

  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
微信小程序中,开发者可以通过微信提供的API接口实现用户登录获取用户手机号。 1. 用户登录 用户登录可以使用微信提供的wx.login()接口,该接口会返回一个临时登录凭证code,开发者可以将该code发送到自己的服务器进行验证,以获取用户的openid信息。 示例代码: ``` wx.login({ success: function(res) { if (res.code) { // 发送 res.code 到后台换取 openId, sessionKey, unionId } else { console.log('登录失败!' + res.errMsg) } } }) ``` 2. 获取用户手机号 获取用户手机号需要先获取用户的授权,可以使用微信提供的wx.getSetting()接口判断用户是否已经授权手机号。如果用户已经授权,则可以使用wx.getUserInfo()接口获取用户信息,其中包括手机号。 示例代码: ``` wx.getSetting({ success(res) { if (!res.authSetting['scope.phoneNumber']) { wx.authorize({ scope: 'scope.phoneNumber', success () { wx.getUserInfo({ success: function(res) { console.log(res) // 可以通过 res.userInfo.phoneNumber 获取用户手机号 } }) } }) } } }) ``` 需要注意的是,获取用户手机号需要用户授权,因此需要在小程序的app.json文件中配置相应的权限,例如: ``` { "mp-weixin": { "appid": "your appid", "permission": { "scope.userLocation": { "desc": "你的位置信息将用于小程序定位" }, "scope.userInfo": { "desc": "你的基本信息将用于小程序登录" }, "scope.userLocationBackground": { "desc": "你的位置信息将在后台运行时持续获取" }, "scope.phoneNumber": { "desc": "获取你的手机号码" } } } } ``` 以上是获取用户手机号的一般流程,开发者可以根据自己的需求进行相应的调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值