第三方登录-google-注册时提取jws里的email赋予account

This commit is contained in:
khalil
2025-07-09 16:00:38 +08:00
parent 827bd4f180
commit d0d6e4b5be
6 changed files with 31 additions and 273 deletions

View File

@@ -11,7 +11,6 @@ import com.baomidou.mybatisplus.extension.service.IService;
*/ */
public interface GoogleOpenidRefService extends IService<GoogleOpenidRef> { public interface GoogleOpenidRefService extends IService<GoogleOpenidRef> {
String getUnionIdByEmail(String email, String idToken); GoogleOpenidRef getRefByEmail(String email, String idToken);
void saveRecord(String email, String openId);
} }

View File

@@ -10,7 +10,6 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.Date; import java.util.Date;
import java.util.Optional;
/** /**
* google关联表 服务实现类 * google关联表 服务实现类
@@ -21,34 +20,29 @@ import java.util.Optional;
@Service @Service
public class GoogleOpenidRefServiceImpl extends ServiceImpl<GoogleOpenidRefMapper, GoogleOpenidRef> implements GoogleOpenidRefService { public class GoogleOpenidRefServiceImpl extends ServiceImpl<GoogleOpenidRefMapper, GoogleOpenidRef> implements GoogleOpenidRefService {
@Autowired @Autowired
private GoogleTokenVerifier googleTokenVerifier; private GoogleTokenVerifier googleTokenVerifier;
@Override @Override
public String getUnionIdByEmail(String email, String idToken) { public GoogleOpenidRef getRefByEmail(String email, String idToken) {
GoogleOpenidRef googleOpenidRef = baseMapper.selectById(email); GoogleOpenidRef googleOpenidRef = baseMapper.selectById(email);
return Optional.ofNullable(googleOpenidRef) if (null != googleOpenidRef){
.map(x -> x.getOpenId()) return googleOpenidRef;
.orElseGet(() -> { }
GoogleTokenVerifier.GoogleUserInfo sub = googleTokenVerifier.verifyAndGetUserInfo(idToken); if (StringUtils.isBlank(idToken)){
if (sub != null && StringUtils.isNotEmpty(sub.getUserId()) && email.equals(sub.getEmail())) { return null;
String userId = sub.getUserId(); }
saveRecord(email, userId); GoogleTokenVerifier.GoogleUserInfo sub = googleTokenVerifier.verifyAndGetUserInfo(idToken);
return userId; if (sub != null && StringUtils.isNotEmpty(sub.getUserId()) && email.equals(sub.getEmail())) {
} googleOpenidRef = new GoogleOpenidRef();
return null; googleOpenidRef.setEmail(sub.getEmail());
}); googleOpenidRef.setOpenId(sub.getUserId());
} googleOpenidRef.setCreateTime(new Date());
baseMapper.insert(googleOpenidRef);
@Override return googleOpenidRef;
public void saveRecord(String email, String openId) { }
GoogleOpenidRef googleOpenidRef = new GoogleOpenidRef(); return null;
googleOpenidRef.setEmail(email);
googleOpenidRef.setOpenId(openId);
googleOpenidRef.setCreateTime(new Date());
baseMapper.insert(googleOpenidRef);
} }
} }

View File

@@ -1,16 +0,0 @@
package com.accompany.oauth2.event;
import org.springframework.context.ApplicationEvent;
/**
*@description 用户注册事件
*@author yangziwen
*@datetime 2019-04-22 15:44
*@since v1.0
*/
public class UserRegisterSuccessEvent extends ApplicationEvent {
public UserRegisterSuccessEvent(Object source) {
super(source);
}
}

View File

@@ -1,51 +0,0 @@
package com.accompany.oauth2.event.listener;
import com.accompany.common.config.WebSecurityConfig;
import com.accompany.common.utils.HttpUtils;
import com.accompany.core.model.Account;
import com.accompany.oauth2.event.UserRegisterSuccessEvent;
import com.google.gson.Gson;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
/**
* 用户注册监听器
*/
//@Component
public class UserRegisterSuccessListener implements ApplicationListener<UserRegisterSuccessEvent> {
private static final Logger logger = LoggerFactory.getLogger(UserRegisterSuccessListener.class);
private Gson gson = new Gson();
@Autowired
WebSecurityConfig webSecurityConfig;
@Override
@Async
public void onApplicationEvent(UserRegisterSuccessEvent userRegisterEvent) {
logger.info("UserRegisterSuccessListener start ==============");
Account account = (Account) userRegisterEvent.getSource();
logger.info("UserRegisterSuccessListener account:{} ==============", account.getUid());
// http通知到business
Map<String, String> params = new HashMap<>();
params.put("data", gson.toJson(account));
params.put("key", webSecurityConfig.getUserRegisterSuccessNotifyKey());
logger.info("UserRegisterSuccessListener params:{}", params);
try {
HttpUtils.doPost(webSecurityConfig.getUserRegisterSuccessNotifyUrl(), params);
} catch (Exception e) {
logger.error("UserRegisterSuccessListener error:{}", e);
}
logger.info("UserRegisterSuccessListener end ==============");
}
}

View File

@@ -1,166 +0,0 @@
package com.accompany.oauth2.event.listener;
import com.accompany.common.redis.RedisKey;
import com.accompany.common.utils.DateTimeUtil;
import com.accompany.core.service.common.JedisService;
import com.accompany.oauth2.event.UserRegisterSuccessEvent;
import com.alibaba.fastjson.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.util.StringUtils;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
/**
* 用户注册预警监听器
*@author yangziwen
*@datetime 2019-04-22 15:54
*@since v1.0
*/
//@Component
public class UserRegisterWarningListener implements ApplicationListener<UserRegisterSuccessEvent> {
private static final Logger logger = LoggerFactory.getLogger(UserRegisterWarningListener.class);
/** 用户注册数默认一级预警比率 */
private static final Double DEFAULT_LEVEL1_RATE = 1.5;
/** 用户注册数默认二级预警比率 */
private static final Double DEFAULT_LEVEL2_RATE = 2.0;
/** 用户注册数默认平均值 */
private static final Double DEFAULT_AVERAGE_NUMBER = 3000.0;
@Autowired
private JedisService jedisService;
@Override
public void onApplicationEvent(UserRegisterSuccessEvent userRegisterEvent) {
// 今天当前注册用户数
String todayStr = DateTimeUtil.getTodayStr();
Long todayRegisterUserNumbers = this.jedisService.hincr(RedisKey.daily_register_user_number.getKey(), todayStr);
Double averageRegisterNumber = this.getAverageRegisterNumber(todayStr);
// 检查是否触发一级预警,如果已经发送过不需要重复预警
String level1WarningRateStr = this.jedisService.get(RedisKey.daily_register_level1_warning_rate.getKey());
Double level1WarningRate = level1WarningRateStr == null ? DEFAULT_LEVEL1_RATE : Double.parseDouble(level1WarningRateStr);
if (todayRegisterUserNumbers > averageRegisterNumber * level1WarningRate && !hasSentLevel1Warning()) {
String warningMessage = "用户注册一级预警,当前注册人数为" + todayRegisterUserNumbers;
this.sendWarningMessage(warningMessage, RedisKey.daily_register_level1_warning_flag.getKey());
return;
}
// 检查是否触发二级预警,如果已经发送过不需要重复预警
String level2WarningRateStr = this.jedisService.get(RedisKey.daily_register_level1_warning_rate.getKey());
Double level2WarningRate = level2WarningRateStr == null ? DEFAULT_LEVEL2_RATE : Double.parseDouble(level2WarningRateStr);
if (todayRegisterUserNumbers > averageRegisterNumber * level2WarningRate && !hasSentLevel2Warning()) {
String warningMessage = "用户注册二级预警,当前注册人数为" + todayRegisterUserNumbers;
this.sendWarningMessage(warningMessage, RedisKey.daily_register_level2_warning_flag.getKey());
return;
}
}
/**
* 是否已发送过二级预警
* @return true/false
*/
private boolean hasSentLevel2Warning() {
String level1WarningStr = this.jedisService.get(RedisKey.daily_register_level2_warning_flag.getKey());
return level1WarningStr == null ? Boolean.FALSE : Boolean.parseBoolean(level1WarningStr);
}
/**
* 是否已发送过一级预警
* @return true/false
*/
private boolean hasSentLevel1Warning() {
String level1WarningStr = this.jedisService.get(RedisKey.daily_register_level1_warning_flag.getKey());
return level1WarningStr == null ? Boolean.FALSE : Boolean.parseBoolean(level1WarningStr);
}
/**
* 发送预警短信信息
* @param message
*/
private void sendWarningMessage(String message, String warningLevel) {
// TODO: 手机号应该设置到配置表sys_config方便后台配置等项目重构完成后修正
String phone = this.jedisService.get(RedisKey.daily_register_warning_phone.getKey());
if (StringUtils.isEmpty(phone)) {
logger.error("USER REGISTER WARNING, MESSAGE={}, WARNING PHONE NOT AVAILABLE", message);
return;
}
String phones = JSONObject.toJSONString(phone.split(","));
try {
//this.netEaseService.sendTemplate(phones, propertyConfig.getTutuAlertSmsTemplateId(), JSONObject.toJSONString(Arrays.asList(message)));
this.updateWarningFlag(warningLevel);
} catch (Exception e) {
logger.error("FAILED TO SEND USER REGISTER WARNING MESSAGE[{}]", message, e);
}
}
/**
* 更新报警标记
* @param warningLevel
*/
private void updateWarningFlag(String warningLevel) {
Date currentTime = Calendar.getInstance().getTime();
Date tomorrow = DateTimeUtil.addDays(currentTime, 1);
Date beginTimeOfTomorrow = DateTimeUtil.getBeginTimeOfDay(tomorrow);
Long expireSeconds = (beginTimeOfTomorrow.getTime() - currentTime.getTime()) / 1000;
this.jedisService.set(warningLevel, Boolean.TRUE.toString(), expireSeconds.intValue());
}
/**
* 计算最近七天日平均注册用户数,去掉最高值
* @param dateStr yyyy-MM-dd 格式的日期字符串
* @return
*/
private Double getAverageRegisterNumber(String dateStr) {
String averageRegisterNumberStr = this.jedisService.hget(RedisKey.daily_register_average_number.getKey(), dateStr);
if (averageRegisterNumberStr != null) {
return Double.parseDouble(averageRegisterNumberStr);
}
List<String> registerNumbers = this.jedisService.hmread(RedisKey.daily_register_user_number.getKey(), this.getLatestSevenDaysStr());
if (registerNumbers == null || registerNumbers.isEmpty()) {
return DEFAULT_AVERAGE_NUMBER;
}
Double maxNumber = 0.0, totalNumber = 0.0;
for (String registerNumberStr : registerNumbers) {
if (StringUtils.isEmpty(registerNumberStr)){
continue;
}
Double registerNumber = Double.parseDouble(registerNumberStr);
totalNumber += registerNumber;
maxNumber = registerNumber > maxNumber ? registerNumber : maxNumber;
}
Double averageRegisterNumber = (totalNumber - maxNumber) / 6;
this.jedisService.hset(RedisKey.daily_register_average_number.getKey(), dateStr, String.valueOf(averageRegisterNumber));
return averageRegisterNumber;
}
/**
* 获取最近七天日期 yyyy-MM-dd 格式的字符串数组
* @return
*/
private String[] getLatestSevenDaysStr() {
Date today = Calendar.getInstance().getTime();
String[] days = new String[7];
for (int i = 0, size = days.length; i < size; i++) {
days[i] = DateTimeUtil.convertDate(DateTimeUtil.addDays(today, -(i + 1)), DateTimeUtil.DEFAULT_DATE_PATTERN);
}
return days;
}
}

View File

@@ -12,6 +12,7 @@ import com.accompany.common.utils.DateTimeUtil;
import com.accompany.common.utils.UUIDUtil; import com.accompany.common.utils.UUIDUtil;
import com.accompany.core.exception.ServiceException; import com.accompany.core.exception.ServiceException;
import com.accompany.core.model.Account; import com.accompany.core.model.Account;
import com.accompany.core.model.GoogleOpenidRef;
import com.accompany.core.model.UserCancelRecord; import com.accompany.core.model.UserCancelRecord;
import com.accompany.core.model.Users; import com.accompany.core.model.Users;
import com.accompany.core.mybatismapper.AccountMapper; import com.accompany.core.mybatismapper.AccountMapper;
@@ -29,7 +30,6 @@ import com.accompany.email.service.EmailService;
import com.accompany.oauth2.constant.LoginTypeEnum; import com.accompany.oauth2.constant.LoginTypeEnum;
import com.accompany.oauth2.dto.DayIpMaxRegisterLimitConfig; import com.accompany.oauth2.dto.DayIpMaxRegisterLimitConfig;
import com.accompany.oauth2.dto.RepeatedDeviceIpRegisterLimitConfig; import com.accompany.oauth2.dto.RepeatedDeviceIpRegisterLimitConfig;
import com.accompany.oauth2.event.UserRegisterSuccessEvent;
import com.accompany.oauth2.exception.CustomOAuth2Exception; import com.accompany.oauth2.exception.CustomOAuth2Exception;
import com.accompany.sms.service.SmsService; import com.accompany.sms.service.SmsService;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
@@ -37,7 +37,6 @@ import com.google.gson.Gson;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
@@ -64,8 +63,6 @@ public class AccountManageService {
@Autowired @Autowired
private AccountService accountService; private AccountService accountService;
@Autowired @Autowired
private ApplicationContext applicationContext;
@Autowired
private UsersBaseService usersBaseService; private UsersBaseService usersBaseService;
@Autowired @Autowired
private UserCancelRecordService userCancelRecordService; private UserCancelRecordService userCancelRecordService;
@@ -145,14 +142,17 @@ public class AccountManageService {
throw new ServiceException(BusiStatus.REQUEST_FAST); throw new ServiceException(BusiStatus.REQUEST_FAST);
} }
boolean googleLogin = LoginTypeEnum.GOOGLE.getValue() == type; String thirdAccountEmail = null;
if (googleLogin) {
String sub = googleOpenidRefService.getUnionIdByEmail(openid, idToken); if (LoginTypeEnum.GOOGLE.getValue() == type) {
if (sub != null) { GoogleOpenidRef ref = googleOpenidRefService.getRefByEmail(openid, idToken);
openid = sub; if (null != ref) {
unionId = sub; openid = ref.getOpenId();
unionId = ref.getOpenId();
thirdAccountEmail = ref.getEmail();
} }
} }
Account account = accountService.getAccountByThird(type, unionId, null); Account account = accountService.getAccountByThird(type, unionId, null);
if (account == null) { if (account == null) {
checkRegisterLimit(deviceInfo.getDeviceId(), ipAddress); checkRegisterLimit(deviceInfo.getDeviceId(), ipAddress);
@@ -172,6 +172,7 @@ public class AccountManageService {
account.setThirdLoginType(type); account.setThirdLoginType(type);
account.setUnionId(unionId); account.setUnionId(unionId);
account.setOpenId(openid); account.setOpenId(openid);
account.setEmail(thirdAccountEmail);
account = fillDeviceInfo(account, deviceInfo); account = fillDeviceInfo(account, deviceInfo);
@@ -186,8 +187,6 @@ public class AccountManageService {
throw new Exception("第三方登录失败,openid=" + openid + ",异常原因code=" + tokenRet.getCode()); throw new Exception("第三方登录失败,openid=" + openid + ",异常原因code=" + tokenRet.getCode());
} }
log.info("TRIGGER USER REGISTER SUCCESS EVENT");
applicationContext.publishEvent(new UserRegisterSuccessEvent(account));
} else { } else {
// 已存在用户先判断account中的unionId是否为空或者不一致如果是的话则更新不是则跳过 // 已存在用户先判断account中的unionId是否为空或者不一致如果是的话则更新不是则跳过
String state = account.getState(); String state = account.getState();
@@ -284,7 +283,7 @@ public class AccountManageService {
log.error("邮件email {} 注册异常,异常原因code {}", email, tokenRet.getCode()); log.error("邮件email {} 注册异常,异常原因code {}", email, tokenRet.getCode());
throw new ServiceException(BusiStatus.SERVERBUSY); throw new ServiceException(BusiStatus.SERVERBUSY);
} }
applicationContext.publishEvent(new UserRegisterSuccessEvent(account));
return account; return account;
} }
@@ -332,8 +331,7 @@ public class AccountManageService {
log.info("手机号码phone=" + phone + "注册异常,异常原因code=" + tokenRet.getCode()); log.info("手机号码phone=" + phone + "注册异常,异常原因code=" + tokenRet.getCode());
throw new Exception("手机号码phone=" + phone + "注册异常,异常原因code=" + tokenRet.getCode()); throw new Exception("手机号码phone=" + phone + "注册异常,异常原因code=" + tokenRet.getCode());
} }
log.info("TRIGGER USER REGISTER SUCCESS EVENT");
applicationContext.publishEvent(new UserRegisterSuccessEvent(account));
return account; return account;
} }