更新登录结构
This commit is contained in:
parent
7d67868635
commit
72c07d2a09
10
api/pom.xml
10
api/pom.xml
@ -35,6 +35,11 @@
|
||||
<artifactId>druid-spring-boot-starter</artifactId>
|
||||
<version>1.2.14</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
<version>2.8.9</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
@ -72,6 +77,11 @@
|
||||
<artifactId>springfox-boot-starter</artifactId>
|
||||
<version>3.0.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.bouncycastle</groupId>
|
||||
<artifactId>bcprov-jdk15on</artifactId>
|
||||
<version>1.57</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
|
@ -0,0 +1,47 @@
|
||||
package me.xiaoyan.point.api.config;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import lombok.SneakyThrows;
|
||||
import me.xiaoyan.point.api.pojo.dto.ApiResult;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.http.server.ServerHttpRequest;
|
||||
import org.springframework.http.server.ServerHttpResponse;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
|
||||
@RestControllerAdvice
|
||||
public class AppResponseConfig implements ResponseBodyAdvice<Object> {
|
||||
@Resource
|
||||
private ObjectMapper objectMapper;
|
||||
|
||||
@Override
|
||||
public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
@Override
|
||||
public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
|
||||
long traceId = 0;
|
||||
List<String> header = serverHttpResponse.getHeaders().get("x-trace-id");
|
||||
if (header != null && header.size() > 0){
|
||||
String xTraceId = header.get(0);
|
||||
if (xTraceId != null) {
|
||||
traceId = Long.valueOf(xTraceId);
|
||||
}
|
||||
}
|
||||
if (o instanceof String) {
|
||||
return objectMapper.writeValueAsString(ApiResult.success(o).setTraceId(traceId));
|
||||
}
|
||||
if (o instanceof ApiResult) {
|
||||
return ((ApiResult) o).setTraceId(traceId);
|
||||
}
|
||||
|
||||
return ApiResult.success(o).setTraceId(traceId);
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
package me.xiaoyan.point.api.config;
|
||||
|
||||
import me.xiaoyan.point.api.error.BizException;
|
||||
import me.xiaoyan.point.api.pojo.dto.ApiResult;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.web.bind.MethodArgumentNotValidException;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
@RestControllerAdvice
|
||||
public class ResponseExceptionConfig {
|
||||
@ExceptionHandler(value = BizException.class) // 要捕获的异常类型
|
||||
@ResponseBody
|
||||
@ResponseStatus(HttpStatus.OK)
|
||||
public ApiResult bizExceptionHandler(HttpServletRequest req, BizException e) {
|
||||
return ApiResult.error(e.getCode(), e.getMessage());
|
||||
}
|
||||
// 参数异常
|
||||
@ExceptionHandler(value = MethodArgumentNotValidException.class) // 要捕获的异常类型
|
||||
@ResponseBody
|
||||
@ResponseStatus(HttpStatus.OK)
|
||||
public ApiResult bizExceptionHandler(HttpServletRequest req, MethodArgumentNotValidException e) {
|
||||
System.out.println(e.getFieldError().getDefaultMessage());
|
||||
return ApiResult.error(1201, e.getBindingResult().getAllErrors().get(0).getDefaultMessage());
|
||||
}
|
||||
|
||||
// 没有单独处理的异常都会被此方法处理
|
||||
@ExceptionHandler(value = Exception.class) // 要捕获的异常类型
|
||||
@ResponseBody
|
||||
@ResponseStatus(HttpStatus.OK)
|
||||
public ApiResult exceptionHandler(HttpServletRequest req, Exception e) {
|
||||
return ApiResult.error(-1, "App Internal Error:" + e.getMessage());
|
||||
}
|
||||
}
|
@ -1,29 +1,29 @@
|
||||
package me.xiaoyan.point.api.controller;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import lombok.SneakyThrows;
|
||||
import org.apache.hc.client5.http.classic.HttpClient;
|
||||
import org.apache.hc.client5.http.classic.methods.HttpGet;
|
||||
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
|
||||
import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;
|
||||
import org.apache.hc.client5.http.impl.classic.HttpClients;
|
||||
import org.apache.hc.core5.http.HttpResponse;
|
||||
import org.apache.hc.core5.http.io.entity.EntityUtils;
|
||||
import org.apache.hc.core5.http.message.BasicClassicHttpResponse;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import me.xiaoyan.point.api.pojo.UserInfo;
|
||||
import me.xiaoyan.point.api.pojo.vo.UserLoginData;
|
||||
import me.xiaoyan.point.api.service.UserInfoService;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.Map;
|
||||
import javax.annotation.Resource;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
@RestController
|
||||
public class WechatController {
|
||||
@Resource
|
||||
private UserInfoService userInfoService;
|
||||
|
||||
// code => openid等信息
|
||||
// 使用wx.login获取到的code进行登录,完成登录后下发用户登录凭证
|
||||
@RequestMapping("/wechat/login")
|
||||
@SneakyThrows
|
||||
public String login(String code) {
|
||||
return null;
|
||||
public UserInfo login(@Validated @RequestBody UserLoginData data) {
|
||||
//@NotNull(message = "登录code不能为空")
|
||||
|
||||
return userInfoService.login(data);
|
||||
}
|
||||
}
|
||||
|
@ -1,18 +1,23 @@
|
||||
package me.xiaoyan.point.api.error;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 自定义的业务异常类
|
||||
*/
|
||||
@Data
|
||||
public class BizException extends RuntimeException {
|
||||
/**
|
||||
* 错误码
|
||||
*/
|
||||
private int code;
|
||||
|
||||
public BizException(int code, String message) {
|
||||
private BizException(int code, String message) {
|
||||
super(message);
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public BizException(Throwable e) {
|
||||
super(e.getMessage());
|
||||
this.code = 500;
|
||||
public static BizException create(String message) {
|
||||
return new BizException(-1, message);
|
||||
}
|
||||
}
|
||||
public static BizException create(int code,String message) {
|
||||
return new BizException(code, message);
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package me.xiaoyan.point.api.pojo.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.ToString;
|
||||
import lombok.experimental.Accessors;
|
||||
import me.xiaoyan.point.api.error.BizException;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@ToString
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class ApiResult implements Serializable {
|
||||
private int code;
|
||||
private String message;
|
||||
private Object data;
|
||||
private long traceId;
|
||||
|
||||
public static ApiResult success(Object data) {
|
||||
return new ApiResult(0, "success", data,0);
|
||||
}
|
||||
|
||||
public static ApiResult error(int code, String message) {
|
||||
return new ApiResult(code, message, null,0);
|
||||
}
|
||||
|
||||
public static ApiResult error(BizException e) {
|
||||
return new ApiResult(e.getCode(), e.getMessage(), null,0);
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
package me.xiaoyan.point.api.pojo.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class CodeSessionData implements Serializable {
|
||||
/**
|
||||
* 用户唯一标识
|
||||
*/
|
||||
private String openid;
|
||||
/**
|
||||
* 会话密钥,用于签名或解密
|
||||
*/
|
||||
private String sessionKey;
|
||||
/**
|
||||
* 用户在开放平台的唯一标识符
|
||||
*/
|
||||
private String unionid;
|
||||
|
||||
private Integer errcode;
|
||||
|
||||
private String errmsg;
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
package me.xiaoyan.point.api.pojo.dto;
|
||||
|
||||
import lombok.*;
|
||||
import lombok.experimental.Accessors;
|
||||
import me.xiaoyan.point.api.pojo.UserInfo;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@Builder
|
||||
@ToString
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class WechatUserInfo implements Serializable {
|
||||
private String openId;
|
||||
private String unionId;
|
||||
private String avatarUrl;
|
||||
private String nickName;
|
||||
private Integer gender;
|
||||
private String city;
|
||||
private String province;
|
||||
private String country;
|
||||
|
||||
public UserInfo getUserinfo() {
|
||||
return UserInfo.builder()
|
||||
.province(province).city(city)
|
||||
.nickname(nickName)
|
||||
.headImage(avatarUrl)
|
||||
.openId(openId)
|
||||
.build();
|
||||
}
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
package me.xiaoyan.point.api.pojo.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
public class UserLoginData implements Serializable {
|
||||
@NotEmpty(message = "encryptedData参数不能为空")
|
||||
private String encryptedData;
|
||||
@NotEmpty(message = "iv参数不能为空")
|
||||
private String iv;
|
||||
@NotEmpty(message = "code参数不能为空")
|
||||
private String code;
|
||||
}
|
@ -2,13 +2,14 @@ package me.xiaoyan.point.api.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import me.xiaoyan.point.api.pojo.UserInfo;
|
||||
import me.xiaoyan.point.api.pojo.vo.UserLoginData;
|
||||
|
||||
public interface UserInfoService extends IService<UserInfo> {
|
||||
|
||||
/**
|
||||
* 用户的登录
|
||||
* @param code 执行wx.login成功后的code
|
||||
* @param data
|
||||
* @return
|
||||
*/
|
||||
public UserInfo login(String code);
|
||||
public UserInfo login(UserLoginData data);
|
||||
}
|
||||
|
@ -4,11 +4,14 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import me.xiaoyan.point.api.util.WechatDecryptDataUtil;
|
||||
import me.xiaoyan.point.api.error.BizException;
|
||||
import me.xiaoyan.point.api.mapper.PointMapper;
|
||||
import me.xiaoyan.point.api.mapper.UserInfoMapper;
|
||||
import me.xiaoyan.point.api.pojo.Point;
|
||||
import me.xiaoyan.point.api.pojo.UserInfo;
|
||||
import me.xiaoyan.point.api.pojo.dto.CodeSessionData;
|
||||
import me.xiaoyan.point.api.pojo.dto.WechatUserInfo;
|
||||
import me.xiaoyan.point.api.pojo.vo.UserLoginData;
|
||||
import me.xiaoyan.point.api.service.PointRecordService;
|
||||
import me.xiaoyan.point.api.service.PointService;
|
||||
import me.xiaoyan.point.api.service.UserInfoService;
|
||||
@ -21,9 +24,6 @@ import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo>
|
||||
@ -63,16 +63,21 @@ public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo>
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public UserInfo login(String code) {
|
||||
String openId = getOpenIdByCode(code);
|
||||
// TODO 获取用户的基本信息
|
||||
|
||||
public UserInfo login(UserLoginData data) {
|
||||
// 使用code换取登录session相关数据
|
||||
CodeSessionData sessionData = getOpenIdByCode(data.getCode());
|
||||
// 使用openid查询用户信息
|
||||
final UserInfo userInfo = this.getBaseMapper().selectOneByOpenId(openId);
|
||||
final UserInfo userInfo = this.getBaseMapper().selectOneByOpenId(sessionData.getOpenid());
|
||||
// 判断用户信息是否存在
|
||||
if (userInfo == null) {
|
||||
// 先解码获取用户数据
|
||||
WechatUserInfo wechatUserInfo = WechatDecryptDataUtil.decryptData(
|
||||
data.getEncryptedData(),
|
||||
sessionData.getSessionKey(),
|
||||
data.getIv()
|
||||
);
|
||||
// 不存在走 第一次登录流程
|
||||
firstLogin(userInfo);
|
||||
firstLogin(wechatUserInfo.getUserinfo());
|
||||
}
|
||||
// 首先
|
||||
return userInfo;
|
||||
@ -88,7 +93,7 @@ public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo>
|
||||
|
||||
// 使用code换取openId
|
||||
@SneakyThrows
|
||||
private String getOpenIdByCode(String code) {
|
||||
private CodeSessionData getOpenIdByCode(String code) {
|
||||
String url = CODE2SESSION + "?appid=" + app_id + "&secret=" + app_secret
|
||||
+ "&js_code=" + code + "&grant_type=authorization_code";
|
||||
try (CloseableHttpClient client = HttpClients.createDefault()) {
|
||||
@ -96,11 +101,11 @@ public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo>
|
||||
final CloseableHttpResponse response = (CloseableHttpResponse) client.execute(get);
|
||||
final String content = EntityUtils.toString(response.getEntity());
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
final Map map = mapper.convertValue(content, Map.class);
|
||||
if ((Integer) map.get("errcode") != 0) {
|
||||
throw new BizException(1101, "换取code失败(" + map.get("errmsg") + ")");
|
||||
final CodeSessionData data = mapper.convertValue(content, CodeSessionData.class);
|
||||
if (data.getErrcode() != 0) {
|
||||
throw BizException.create(1101, "换取code失败(" + data.getErrmsg() + ")");
|
||||
}
|
||||
return map.get("openid").toString();
|
||||
return data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,82 @@
|
||||
package me.xiaoyan.point.api.util;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import me.xiaoyan.point.api.pojo.dto.WechatUserInfo;
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.spec.IvParameterSpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.security.Key;
|
||||
import java.security.Security;
|
||||
import java.util.Arrays;
|
||||
import java.util.Base64;
|
||||
|
||||
/**
|
||||
* 微信工具类
|
||||
*/
|
||||
public class WechatDecryptDataUtil {
|
||||
|
||||
public static WechatUserInfo decryptData(String encryptDataB64, String sessionKeyB64, String ivB64) {
|
||||
String result = new String(
|
||||
decryptOfDiyIV(
|
||||
Base64.getDecoder().decode(encryptDataB64),
|
||||
Base64.getDecoder().decode(sessionKeyB64),
|
||||
Base64.getDecoder().decode(ivB64)
|
||||
)
|
||||
);
|
||||
if(!StringUtils.hasLength(result)){
|
||||
throw new RuntimeException("解码失败");
|
||||
}
|
||||
return (new Gson()).fromJson(result,WechatUserInfo.class);
|
||||
}
|
||||
|
||||
private static final String KEY_ALGORITHM = "AES";
|
||||
private static final String ALGORITHM_STR = "AES/CBC/PKCS7Padding";
|
||||
private static Key key;
|
||||
private static Cipher cipher;
|
||||
|
||||
private static void init(byte[] keyBytes) {
|
||||
// 如果密钥不足16位,那么就补足. 这个if 中的内容很重要
|
||||
int base = 16;
|
||||
if (keyBytes.length % base != 0) {
|
||||
int groups = keyBytes.length / base + (keyBytes.length % base != 0 ? 1 : 0);
|
||||
byte[] temp = new byte[groups * base];
|
||||
Arrays.fill(temp, (byte) 0);
|
||||
System.arraycopy(keyBytes, 0, temp, 0, keyBytes.length);
|
||||
keyBytes = temp;
|
||||
}
|
||||
// 初始化
|
||||
Security.addProvider(new BouncyCastleProvider());
|
||||
// 转化成JAVA的密钥格式
|
||||
key = new SecretKeySpec(keyBytes, KEY_ALGORITHM);
|
||||
try {
|
||||
// 初始化cipher
|
||||
cipher = Cipher.getInstance(ALGORITHM_STR, "BC");
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解密方法
|
||||
*
|
||||
* @param encryptedData 要解密的字符串
|
||||
* @param keyBytes 解密密钥
|
||||
* @param ivs 自定义对称解密算法初始向量 iv
|
||||
* @return 解密后的字节数组
|
||||
*/
|
||||
private static byte[] decryptOfDiyIV(byte[] encryptedData, byte[] keyBytes, byte[] ivs) {
|
||||
byte[] encryptedText = null;
|
||||
init(keyBytes);
|
||||
try {
|
||||
cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(ivs));
|
||||
encryptedText = cipher.doFinal(encryptedData);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return encryptedText;
|
||||
}
|
||||
|
||||
}
|
26
api/src/test/java/me/xiaoyan/point/api/WechatTests.java
Normal file
26
api/src/test/java/me/xiaoyan/point/api/WechatTests.java
Normal file
@ -0,0 +1,26 @@
|
||||
package me.xiaoyan.point.api;
|
||||
|
||||
import me.xiaoyan.point.api.pojo.dto.WechatUserInfo;
|
||||
import me.xiaoyan.point.api.util.WechatDecryptDataUtil;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class WechatTests {
|
||||
|
||||
|
||||
@DisplayName("解密用户信息")
|
||||
@Test
|
||||
void testDecode(){
|
||||
String encryptedData = "Ezl1S3BHjBeg/HP0Nim/c9eLLYP5L1kgvqSpR+RQYFG6c3Qx0K5U6btEY5IByCw1OsnZ0hKDccNJn3VA/ZgpkxjDODt+XLcph3KqEL6LDU9BLDRFxCI7u+eHBorz5HWYzGITXiuyPb9NWmGAPXwwp0abFqqaycb5u4oii7I/tnh7NIRIcMxAft1YfbVdzQDjraRHFH5hg6Eh4RGSjy6rg1bG/sMecw4+XWM1psTjKBYNwtsG5oxBWja6DniPhmWU6ZwjVMfgJX5Z7wcw2vtmuDPOMCEE1SEcwmTcQ5YKLlPsPBAJhrF3Lxg9oTD1/IlZ";
|
||||
String iv = "ckSRPBLA61WONzUDINIWMg==";
|
||||
|
||||
|
||||
WechatUserInfo wechatUserInfo = WechatDecryptDataUtil.decryptData(
|
||||
"SCK0Ik7THl+USkwTRqTQ9BYGe6rWlXosQ8fWA3I3AsFHTCuPnjbsjFooIEZVcS6mq911XeP5BJJBpPU6A1O3aNuC9L7ebXqTMQX83bVBtaDQySvCIlyyq26xhm8AbWWexl5994NJDpKkNml9ilbYia99bF8bXzXvLCksQQkz82EpZTqztzmCrTdFBZOIrJ+lDnl7rSBWJvVVtoagzgSq2Ux59LcJtxCukIUoZ8fz54//Hm4GhrLucO4zPKTi087f77Pd9K9Rz3LLJ79NMQHHQLtZ38Ws79IKoHBZ7xHXbl3O8xPeTBrrWeHbNfNs1CbOyoe0RwXVjs/fMR9451PeLVM5jg4fj3IDyTFjpx5aUzQRaIrSY/BjVFJoxU/viwQC6LsCBOyXl5uV5h+qIPC5suFbmhl5Q56eU07wbOjNxktEIJsIgbrT+GWRZVPba3dUo+6RoZySxCMA16TRKfuTwjXceV3oNueFdTNyw05s9N43OkrLeKcz1dFeNnpA9DHEVngB1J7MY4RkazdKaWzrld1DjxW6+rk01GgtAr3+H88=",
|
||||
"PKX9EeH6y+pzz8qYrga2jQ==",
|
||||
"Ql/m+Ksll5ziCCZj+07J6g=="
|
||||
|
||||
);
|
||||
System.out.println(wechatUserInfo);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user