|
@@ -0,0 +1,183 @@
|
|
|
|
|
+package com.jeesite.modules.mes.service;
|
|
|
|
|
+
|
|
|
|
|
+import com.jeesite.common.config.Global;
|
|
|
|
|
+import com.jeesite.common.idgen.IdGen;
|
|
|
|
|
+import com.jeesite.common.lang.StringUtils;
|
|
|
|
|
+import com.jeesite.common.service.CrudService;
|
|
|
|
|
+import com.jeesite.modules.mes.dao.MesEmailLoginCodeDao;
|
|
|
|
|
+import com.jeesite.modules.mes.entity.MesEmailLoginCode;
|
|
|
|
|
+import com.jeesite.modules.mes.util.MailUtil;
|
|
|
|
|
+import com.jeesite.modules.sys.entity.User;
|
|
|
|
|
+import com.jeesite.modules.sys.utils.UserUtils;
|
|
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
|
|
+import org.springframework.transaction.annotation.Transactional;
|
|
|
|
|
+
|
|
|
|
|
+import java.text.SimpleDateFormat;
|
|
|
|
|
+import java.util.Calendar;
|
|
|
|
|
+import java.util.Date;
|
|
|
|
|
+import java.util.Random;
|
|
|
|
|
+import java.util.regex.Pattern;
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * MES email login verification code service.
|
|
|
|
|
+ */
|
|
|
|
|
+@Service
|
|
|
|
|
+public class MesEmailLoginCodeService extends CrudService<MesEmailLoginCodeDao, MesEmailLoginCode> {
|
|
|
|
|
+
|
|
|
|
|
+ public static final String LOGIN_SUCCESS = "SUCCESS";
|
|
|
|
|
+ public static final String LOGIN_ACCOUNT_PASSWORD_ERROR = "ACCOUNT_PASSWORD_ERROR";
|
|
|
|
|
+ public static final String LOGIN_EMAIL_MISMATCH = "EMAIL_MISMATCH";
|
|
|
|
|
+ public static final String LOGIN_CODE_EXPIRED = "CODE_EXPIRED";
|
|
|
|
|
+ public static final String LOGIN_CODE_ERROR = "CODE_ERROR";
|
|
|
|
|
+
|
|
|
|
|
+ private static final Pattern EMAIL_PATTERN = Pattern.compile("^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$");
|
|
|
|
|
+ private static final Pattern CODE_PATTERN = Pattern.compile("^\\d{6}$");
|
|
|
|
|
+ private static final int EXPIRE_MINUTES = 5;
|
|
|
|
|
+ private static final int SEND_INTERVAL_SECONDS = 60;
|
|
|
|
|
+ private static final int DAILY_LIMIT = 200;
|
|
|
|
|
+
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private MesEmailLoginCodeDao mesEmailLoginCodeDao;
|
|
|
|
|
+
|
|
|
|
|
+ public boolean isEmailLoginEnabled() {
|
|
|
|
|
+ return "1".equals(Global.getConfig("mes.email.controller"));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public boolean isEmailFormat(String email) {
|
|
|
|
|
+ return StringUtils.isNotBlank(email) && EMAIL_PATTERN.matcher(email).matches();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public boolean isBoundEmail(User user, String email) {
|
|
|
|
|
+ return user != null && StringUtils.isNotBlank(user.getEmail()) && StringUtils.equalsIgnoreCase(StringUtils.trim(user.getEmail()), StringUtils.trim(email));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Transactional
|
|
|
|
|
+ public String sendCode(String loginCode, String email) {
|
|
|
|
|
+ loginCode = StringUtils.trim(loginCode);
|
|
|
|
|
+ email = StringUtils.trim(email);
|
|
|
|
|
+ if (StringUtils.isBlank(loginCode)) {
|
|
|
|
|
+ return "请先填写登录账号。";
|
|
|
|
|
+ }
|
|
|
|
|
+ if (!isEmailFormat(email)) {
|
|
|
|
|
+ return "请填写正确的绑定邮箱。";
|
|
|
|
|
+ }
|
|
|
|
|
+ User user = UserUtils.getByLoginCode(loginCode);
|
|
|
|
|
+ if (user == null || !"0".equals(user.getStatus())) {
|
|
|
|
|
+ return "账号密码错误。";
|
|
|
|
|
+ }
|
|
|
|
|
+ if (StringUtils.isBlank(user.getEmail())) {
|
|
|
|
|
+ return "该账号未绑定邮箱,禁止登录。";
|
|
|
|
|
+ }
|
|
|
|
|
+ if (!isBoundEmail(user, email)) {
|
|
|
|
|
+ return "邮箱与账号不匹配。";
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ Date now = new Date();
|
|
|
|
|
+ if (mesEmailLoginCodeDao.countSentSince(email, format(addSeconds(now, -SEND_INTERVAL_SECONDS))) > 0) {
|
|
|
|
|
+ return "单个邮箱1分钟仅可发送1次验证码,请稍后再试。";
|
|
|
|
|
+ }
|
|
|
|
|
+ String dayStart = format(startOfDay(now));
|
|
|
|
|
+ String dayEnd = format(addDays(startOfDay(now), 1));
|
|
|
|
|
+ if (mesEmailLoginCodeDao.countSentToday(email, dayStart, dayEnd) >= DAILY_LIMIT) {
|
|
|
|
|
+ return "单个邮箱单日最多发送200次验证码。";
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ MesEmailLoginCode emailLoginCode = new MesEmailLoginCode();
|
|
|
|
|
+ emailLoginCode.setId(IdGen.randomBase62(19));
|
|
|
|
|
+ emailLoginCode.setIsNewRecord(true);
|
|
|
|
|
+ emailLoginCode.setLoginCode(loginCode);
|
|
|
|
|
+ emailLoginCode.setEmail(email);
|
|
|
|
|
+ emailLoginCode.setCode(randomCode());
|
|
|
|
|
+ emailLoginCode.setSendDate(now);
|
|
|
|
|
+ emailLoginCode.setExpireDate(addMinutes(now, EXPIRE_MINUTES));
|
|
|
|
|
+ emailLoginCode.setStatus("0");
|
|
|
|
|
+ save(emailLoginCode);
|
|
|
|
|
+
|
|
|
|
|
+ new Thread(new MailUtil(email, emailLoginCode.getCode())).start();
|
|
|
|
|
+ return null;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Transactional
|
|
|
|
|
+ public String validateCode(String loginCode, String email, String code) {
|
|
|
|
|
+ loginCode = StringUtils.trim(loginCode);
|
|
|
|
|
+ email = StringUtils.trim(email);
|
|
|
|
|
+ code = StringUtils.trim(code);
|
|
|
|
|
+ User user = UserUtils.getByLoginCode(loginCode);
|
|
|
|
|
+ if (user == null || !"0".equals(user.getStatus())) {
|
|
|
|
|
+ return LOGIN_ACCOUNT_PASSWORD_ERROR;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (StringUtils.isBlank(user.getEmail()) || !isBoundEmail(user, email)) {
|
|
|
|
|
+ return LOGIN_EMAIL_MISMATCH;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (!CODE_PATTERN.matcher(code).matches()) {
|
|
|
|
|
+ return LOGIN_CODE_ERROR;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ MesEmailLoginCode latest = mesEmailLoginCodeDao.findLatest(loginCode, email);
|
|
|
|
|
+ if (latest == null) {
|
|
|
|
|
+ return LOGIN_CODE_ERROR;
|
|
|
|
|
+ }
|
|
|
|
|
+ Date now = new Date();
|
|
|
|
|
+ if (latest.getExpireDate() == null || latest.getExpireDate().before(now)) {
|
|
|
|
|
+ if ("0".equals(latest.getStatus())) {
|
|
|
|
|
+ mesEmailLoginCodeDao.markExpired(latest.getId());
|
|
|
|
|
+ }
|
|
|
|
|
+ return LOGIN_CODE_EXPIRED;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (!"0".equals(latest.getStatus())) {
|
|
|
|
|
+ return LOGIN_CODE_ERROR;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (!StringUtils.equals(latest.getCode(), code)) {
|
|
|
|
|
+ return LOGIN_CODE_ERROR;
|
|
|
|
|
+ }
|
|
|
|
|
+ return LOGIN_SUCCESS;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Transactional
|
|
|
|
|
+ public void markLatestCodeUsed(String loginCode, String email) {
|
|
|
|
|
+ MesEmailLoginCode latest = mesEmailLoginCodeDao.findLatestUnused(StringUtils.trim(loginCode), StringUtils.trim(email));
|
|
|
|
|
+ if (latest != null) {
|
|
|
|
|
+ mesEmailLoginCodeDao.markUsed(latest.getId());
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private String randomCode() {
|
|
|
|
|
+ return String.format("%06d", new Random().nextInt(1000000));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private Date addMinutes(Date date, int minutes) {
|
|
|
|
|
+ Calendar calendar = Calendar.getInstance();
|
|
|
|
|
+ calendar.setTime(date);
|
|
|
|
|
+ calendar.add(Calendar.MINUTE, minutes);
|
|
|
|
|
+ return calendar.getTime();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private Date addSeconds(Date date, int seconds) {
|
|
|
|
|
+ Calendar calendar = Calendar.getInstance();
|
|
|
|
|
+ calendar.setTime(date);
|
|
|
|
|
+ calendar.add(Calendar.SECOND, seconds);
|
|
|
|
|
+ return calendar.getTime();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private Date addDays(Date date, int days) {
|
|
|
|
|
+ Calendar calendar = Calendar.getInstance();
|
|
|
|
|
+ calendar.setTime(date);
|
|
|
|
|
+ calendar.add(Calendar.DATE, days);
|
|
|
|
|
+ return calendar.getTime();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private Date startOfDay(Date date) {
|
|
|
|
|
+ Calendar calendar = Calendar.getInstance();
|
|
|
|
|
+ calendar.setTime(date);
|
|
|
|
|
+ calendar.set(Calendar.HOUR_OF_DAY, 0);
|
|
|
|
|
+ calendar.set(Calendar.MINUTE, 0);
|
|
|
|
|
+ calendar.set(Calendar.SECOND, 0);
|
|
|
|
|
+ calendar.set(Calendar.MILLISECOND, 0);
|
|
|
|
|
+ return calendar.getTime();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private String format(Date date) {
|
|
|
|
|
+ return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date);
|
|
|
|
|
+ }
|
|
|
|
|
+}
|