完善小程序解密获取手机号,更新系统用户名功能

This commit is contained in:
wanggeng 2021-08-03 10:58:12 +08:00
parent 12fc61234a
commit 23e8164b2d
14 changed files with 277 additions and 104 deletions

View File

@ -15,7 +15,7 @@ import org.springframework.context.annotation.Configuration;
**/
@Configuration
@ConfigurationProperties(prefix = "open-platform.wechat.mini-app")
public class MiniAppProperties {
public class MiniappProperties {
private Boolean active;
private String authorizeUrl;

View File

@ -62,7 +62,7 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
"/approute/**",
"/wechat/**",
"/wechat/route/**",
"/wechat/miniapp/**",
"/wechat-miniapp/**",
"/route/file/**",
"/api/sms/getverificationcode/*",
"/api/user/getsignintype/**")

View File

@ -2,8 +2,8 @@ package ink.wgink.login.wechat.controller.app;
import ink.wgink.annotation.CheckRequestBodyAnnotation;
import ink.wgink.interfaces.consts.ISystemConstant;
import ink.wgink.login.wechat.pojo.vos.update.MiniappUpdatePhoneVO;
import ink.wgink.login.wechat.service.sign.IMiniappSignService;
import ink.wgink.module.wechat.pojo.vos.miniapp.MiniappUpdatePhoneVO;
import ink.wgink.pojo.result.ErrorResult;
import ink.wgink.pojo.result.SuccessResultData;
import io.swagger.annotations.*;

View File

@ -7,7 +7,7 @@ import ink.wgink.login.wechat.pojo.vos.sign.MiniappLoginVO;
import ink.wgink.login.wechat.service.sign.IMiniappSignService;
import ink.wgink.pojo.result.ErrorResult;
import ink.wgink.pojo.result.SuccessResultData;
import ink.wgink.properties.wechat.miniapp.MiniAppProperties;
import ink.wgink.properties.wechat.miniapp.MiniappProperties;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiResponse;
@ -34,7 +34,7 @@ import org.springframework.web.bind.annotation.RestController;
public class SignMiniappController {
@Autowired
private MiniAppProperties miniAppProperties;
private MiniappProperties miniAppProperties;
@Autowired
private IMiniappSignService miniAppSignService;

View File

@ -0,0 +1,81 @@
package ink.wgink.login.wechat.pojo.bos.miniapp;
/**
* @ClassName: MiniappPhoneBO
* @Description: 小程序手机号
* @Author: wanggeng
* @Date: 2021/8/3 10:46 上午
* @Version: 1.0
*/
public class MiniappPhoneDataBO {
private String phoneNumber;
private String purePhoneNumber;
private String countryCode;
private WaterMark watermark;
public String getPhoneNumber() {
return phoneNumber == null ? "" : phoneNumber.trim();
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
public String getPurePhoneNumber() {
return purePhoneNumber == null ? "" : purePhoneNumber.trim();
}
public void setPurePhoneNumber(String purePhoneNumber) {
this.purePhoneNumber = purePhoneNumber;
}
public String getCountryCode() {
return countryCode == null ? "" : countryCode.trim();
}
public void setCountryCode(String countryCode) {
this.countryCode = countryCode;
}
public WaterMark getWatermark() {
return watermark;
}
public void setWatermark(WaterMark watermark) {
this.watermark = watermark;
}
public static class WaterMark {
private String appid;
private Long timestamp;
public String getAppid() {
return appid == null ? "" : appid.trim();
}
public void setAppid(String appid) {
this.appid = appid;
}
public Long getTimestamp() {
return timestamp;
}
public void setTimestamp(Long timestamp) {
this.timestamp = timestamp;
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("{");
sb.append("\"appid\":\"")
.append(appid).append('\"');
sb.append(",\"timestamp\":")
.append(timestamp);
sb.append('}');
return sb.toString();
}
}
}

View File

@ -0,0 +1,50 @@
package ink.wgink.login.wechat.pojo.vos.update;
import ink.wgink.annotation.CheckEmptyAnnotation;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
/**
* @ClassName: MiniAppUpdatePhoneVO
* @Description: 小程序更新手机
* @Author: wanggeng
* @Date: 2021/8/2 5:20 下午
* @Version: 1.0
*/
@ApiModel
public class MiniappUpdatePhoneVO {
@ApiModelProperty(name = "encryptedData", value = "加密数据")
@CheckEmptyAnnotation(name = "加密数据")
private String encryptedData;
@ApiModelProperty(name = "iv", value = "向量")
@CheckEmptyAnnotation(name = "iv")
private String iv;
public String getEncryptedData() {
return encryptedData == null ? "" : encryptedData.trim();
}
public void setEncryptedData(String encryptedData) {
this.encryptedData = encryptedData;
}
public String getIv() {
return iv == null ? "" : iv.trim();
}
public void setIv(String iv) {
this.iv = iv;
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("{");
sb.append("\"encryptedData\":\"")
.append(encryptedData).append('\"');
sb.append(",\"iv\":\"")
.append(iv).append('\"');
sb.append('}');
return sb.toString();
}
}

View File

@ -1,37 +0,0 @@
package ink.wgink.login.wechat.pojo.vos.update;
import ink.wgink.annotation.CheckEmptyAnnotation;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
/**
* @ClassName: MiniAppUpdatePhoneVO
* @Description: 小程序更新手机
* @Author: wanggeng
* @Date: 2021/8/2 5:20 下午
* @Version: 1.0
*/
@ApiModel
public class UpdatePhoneVO {
@ApiModelProperty(name = "phone", value = "手机号")
@CheckEmptyAnnotation(name = "手机号", regex = "phone")
private String phone;
public String getPhone() {
return phone == null ? "" : phone.trim();
}
public void setPhone(String phone) {
this.phone = phone;
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("{");
sb.append("\"phone\":\"")
.append(phone).append('\"');
sb.append('}');
return sb.toString();
}
}

View File

@ -1,7 +1,7 @@
package ink.wgink.login.wechat.service.sign;
import ink.wgink.login.wechat.pojo.vos.sign.MiniappLoginVO;
import ink.wgink.module.wechat.pojo.vos.miniapp.MiniappUpdatePhoneVO;
import ink.wgink.login.wechat.pojo.vos.update.MiniappUpdatePhoneVO;
import java.io.UnsupportedEncodingException;

View File

@ -7,16 +7,20 @@ import ink.wgink.exceptions.WechatAccessTokenForUserException;
import ink.wgink.exceptions.WechatUserInfoException;
import ink.wgink.interfaces.consts.ISystemConstant;
import ink.wgink.login.base.service.BaseAppSignService;
import ink.wgink.login.wechat.pojo.bos.miniapp.MiniappPhoneDataBO;
import ink.wgink.login.wechat.pojo.vos.sign.MiniappLoginVO;
import ink.wgink.login.wechat.pojo.vos.update.MiniappUpdatePhoneVO;
import ink.wgink.login.wechat.service.sign.IMiniappSignService;
import ink.wgink.module.wechat.pojo.bos.miniapp.MiniAppUserInfoBO;
import ink.wgink.module.wechat.manager.MiniappManager;
import ink.wgink.module.wechat.pojo.bos.miniapp.MiniappUserInfoBO;
import ink.wgink.module.wechat.pojo.pos.miniapp.MiniappUserPO;
import ink.wgink.module.wechat.pojo.vos.miniapp.MiniappUpdatePhoneVO;
import ink.wgink.module.wechat.service.miniapp.IMiniappUserService;
import ink.wgink.properties.wechat.miniapp.MiniAppProperties;
import ink.wgink.properties.wechat.miniapp.MiniappProperties;
import ink.wgink.service.user.pojo.pos.UserPO;
import ink.wgink.service.user.pojo.vos.UpdateUsernameVO;
import ink.wgink.service.user.service.IUserService;
import ink.wgink.util.AesUtil;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
@ -41,7 +45,7 @@ import java.util.Map;
public class MiniappSignServiceImpl extends BaseAppSignService implements IMiniappSignService {
@Autowired
private MiniAppProperties miniappProperties;
private MiniappProperties miniappProperties;
@Autowired
private IMiniappUserService miniappUserService;
@Autowired
@ -63,7 +67,7 @@ public class MiniappSignServiceImpl extends BaseAppSignService implements IMinia
RestTemplate restTemplate = new RestTemplate();
String resultJson = restTemplate.getForObject(url.toString(), String.class, params);
MiniAppUserInfoBO miniAppUserInfoBO = JSONObject.parseObject(resultJson, MiniAppUserInfoBO.class);
MiniappUserInfoBO miniAppUserInfoBO = JSONObject.parseObject(resultJson, MiniappUserInfoBO.class);
if (miniAppUserInfoBO == null) {
throw new WechatUserInfoException("获取微信用户信息失败");
}
@ -76,17 +80,22 @@ public class MiniappSignServiceImpl extends BaseAppSignService implements IMinia
if (userPO == null) {
throw new SearchException("用户不存在");
}
String token = getMiniappToken(userPO);
// 加入管理队列
MiniappManager.getInstance().addUser(token.substring(0, token.length() - 2), miniAppUserInfoBO);
return getMiniappToken(userPO);
}
@Override
public String updatePhone(String token, MiniappUpdatePhoneVO miniappUpdatePhoneVO) throws UnsupportedEncodingException {
MiniappPhoneDataBO miniappPhoneData = getMiniappPhoneData(token, miniappUpdatePhoneVO);
String userId = getAppTokenUser(token).getId();
UserPO userPO = userService.getPO(userId);
if (userPO == null) {
throw new SearchException("非系统用户,请刷新小程序");
}
UserPO userPOByUsername = userService.getPOByUsername(miniappUpdatePhoneVO.getPhone());
String phone = miniappPhoneData.getPhoneNumber();
UserPO userPOByUsername = userService.getPOByUsername(phone);
if (userPOByUsername != null) {
LOG.debug("手机号存在");
// 不是当前用户抛异常
@ -103,17 +112,36 @@ public class MiniappSignServiceImpl extends BaseAppSignService implements IMinia
}
LOG.debug("手机不存在,更新用户名");
UpdateUsernameVO updateUsernameVO = new UpdateUsernameVO();
updateUsernameVO.setUsername(miniappUpdatePhoneVO.getPhone());
updateUsernameVO.setUsername(phone);
updateUsernameVO.setUpdateReason("微信用户手动更新");
userService.updateUsername(userId, updateUsernameVO);
LOG.debug("返回token");
UserPO newUserPO = new UserPO();
BeanUtils.copyProperties(userPO, newUserPO);
newUserPO.setUserUsername(miniappUpdatePhoneVO.getPhone());
newUserPO.setUserUsername(phone);
miniappUserService.updateIsInitAccount(userId, 0);
return getMiniappToken(userPO);
}
/**
* 解密获得手机号
*
* @param token
* @param miniappUpdatePhoneVO
* @return
*/
private MiniappPhoneDataBO getMiniappPhoneData(String token, MiniappUpdatePhoneVO miniappUpdatePhoneVO) {
MiniappUserInfoBO miniappUserInfoBO = MiniappManager.getInstance().get(token);
if (miniappUserInfoBO == null) {
throw new SearchException("会话不存在,请重新打开小程序");
}
byte[] encryptedBytes = Base64.decodeBase64(miniappUpdatePhoneVO.getEncryptedData());
byte[] keyBytes = Base64.decodeBase64(miniappUserInfoBO.getSession_key());
byte[] ivBytes = Base64.decodeBase64(miniappUpdatePhoneVO.getIv());
byte[] userInfoBytes = AesUtil.aesCommonDecoderDetail(keyBytes, encryptedBytes, ivBytes, AesUtil.PKCS_7);
return JSONObject.parseObject(userInfoBytes, MiniappPhoneDataBO.class);
}
/**
* 获得小程序token
*

View File

@ -0,0 +1,82 @@
package ink.wgink.module.wechat.manager;
import ink.wgink.module.wechat.pojo.bos.miniapp.MiniappUserInfoBO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* When you feel like quitting. Think about why you started
* 当你想要放弃的时候想想当初你为何开始
*
* @ClassName: WechatMiniAppManager
* @Description: 微信小程序管理
* @Author: WangGeng
* @Date: 2020/5/9 18:05
* @Version: 1.0
**/
public class MiniappManager {
private static final Logger LOG = LoggerFactory.getLogger(MiniappManager.class);
private static MiniappManager miniAppManager = WechatMiniAppManagerBuilder.MINI_APP_MANAGER;
// 超时分钟
private final int TIME_OUT_SECOND = 120 * 60;
private MiniappManager() {
}
private Map<String, MiniappUserInfoBO> users = new ConcurrentHashMap<>();
public static MiniappManager getInstance() {
return miniAppManager;
}
/**
* 添加用户
*
* @param token
* @param miniappUserInfoBO
*/
public void addUser(String token, MiniappUserInfoBO miniappUserInfoBO) {
miniappUserInfoBO.setUpdateTime(System.currentTimeMillis());
users.put(token, miniappUserInfoBO);
}
/**
* 获取小程序应用
*
* @param token
* @return
*/
public MiniappUserInfoBO get(String token) {
return users.get(token);
}
/**
* 删除超时用户
*/
public void removeTimeout() {
LOG.debug("delete timeout wechat mini app user start");
long startTime = System.currentTimeMillis();
List<String> tokenList = new ArrayList<>();
for (Map.Entry<String, MiniappUserInfoBO> kv : users.entrySet()) {
// 超时
if ((startTime - kv.getValue().getUpdateTime()) / 1000 > TIME_OUT_SECOND) {
tokenList.add(kv.getKey());
}
}
for (String token : tokenList) {
users.remove(token);
}
long endTime = System.currentTimeMillis();
LOG.debug("delete timeout wechat mini app user end, delete count: {}, useTime: {}ms", tokenList.size(), endTime - startTime);
}
private static class WechatMiniAppManagerBuilder {
public static final MiniappManager MINI_APP_MANAGER = new MiniappManager();
}
}

View File

@ -10,7 +10,7 @@ package ink.wgink.module.wechat.pojo.bos.miniapp;
* @Date: 2020/5/9 18:29
* @Version: 1.0
**/
public class MiniAppUserInfoBO {
public class MiniappUserInfoBO {
private String openid;
private String session_key;

View File

@ -1,37 +0,0 @@
package ink.wgink.module.wechat.pojo.vos.miniapp;
import ink.wgink.annotation.CheckEmptyAnnotation;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
/**
* @ClassName: MiniAppUpdatePhoneVO
* @Description: 小程序更新手机
* @Author: wanggeng
* @Date: 2021/8/2 5:20 下午
* @Version: 1.0
*/
@ApiModel
public class MiniappUpdatePhoneVO {
@ApiModelProperty(name = "phone", value = "手机号")
@CheckEmptyAnnotation(name = "手机号", regex = "phone")
private String phone;
public String getPhone() {
return phone == null ? "" : phone.trim();
}
public void setPhone(String phone) {
this.phone = phone;
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("{");
sb.append("\"phone\":\"")
.append(phone).append('\"');
sb.append('}');
return sb.toString();
}
}

View File

@ -1,9 +1,8 @@
package ink.wgink.module.wechat.startup;
import ink.wgink.module.wechat.dao.miniapp.IMiniAppUserDao;
import ink.wgink.module.wechat.dao.official.account.IOfficialAccountUserDao;
import ink.wgink.module.wechat.manager.MiniappManager;
import ink.wgink.module.wechat.manager.OfficialAccountAccessTokenManager;
import ink.wgink.properties.wechat.miniapp.MiniAppProperties;
import ink.wgink.properties.wechat.miniapp.MiniappProperties;
import ink.wgink.properties.wechat.official.account.OfficialAccountProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -27,17 +26,15 @@ import org.springframework.stereotype.Component;
public class WechatStartUp implements ApplicationRunner {
private static final Logger LOG = LoggerFactory.getLogger(WechatStartUp.class);
@Autowired
private MiniAppProperties miniAppProperties;
private MiniappProperties miniAppProperties;
@Autowired
private OfficialAccountProperties officialAccountProperties;
@Autowired
private IMiniAppUserDao miniAppUserDao;
@Autowired
private IOfficialAccountUserDao officialAccountUserDao;
@Override
public void run(ApplicationArguments args) throws Exception {
new Thread(() -> refreshOfficialAccountAccessToken()).start();
new Thread(() -> {
refreshOfficialAccountAccessToken();
}).start();
}
@Scheduled(cron = "0 0/5 * * * ?")
@ -48,4 +45,15 @@ public class WechatStartUp implements ApplicationRunner {
OfficialAccountAccessTokenManager.getInstance().refreshAccessToken(officialAccountProperties);
}
/**
* 删除小程序超时用户每10分钟执行一次
*/
@Scheduled(cron = "0 0/10 * * * ?")
public void removeTimeoutMiniAppUser() {
if (!miniAppProperties.getActive()) {
return;
}
MiniappManager.getInstance().removeTimeout();
}
}

View File

@ -31,7 +31,7 @@
</update>
<!-- 保存 -->
<insert id="save" parameterType="map">
<insert id="save" parameterType="map" flushCache="true">
INSERT INTO wechat_mini_app_user(
app_id,
open_id,
@ -48,7 +48,7 @@
</insert>
<!-- 更新信息 -->
<update id="updateInfo" parameterType="map">
<update id="updateInfo" parameterType="map" flushCache="true">
UPDATE
wechat_mini_app_user
SET
@ -61,7 +61,7 @@
</update>
<!-- 更新是否初始化账号 -->
<update id="updateIsInitAccount" parameterType="map">
<update id="updateIsInitAccount" parameterType="map" flushCache="true">
UPDATE
wechat_mini_app_user
SET
@ -110,7 +110,7 @@
<if test="appId != null and appId != ''">
app_id = #{appId}
</if>
<if test="openId != '' and openId != ''">
<if test="openId != null and openId != ''">
AND
open_id = #{openId}
</if>
@ -121,6 +121,4 @@
</where>
</select>
</mapper>