1.添加邮箱验证
This commit is contained in:
BIN
.idea/.cache/.Apifox_Helper/.toolWindow.db
generated
BIN
.idea/.cache/.Apifox_Helper/.toolWindow.db
generated
Binary file not shown.
16
src/main/java/vvpkassistant/Tools/CacheHolder.java
Normal file
16
src/main/java/vvpkassistant/Tools/CacheHolder.java
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
package vvpkassistant.Tools;
|
||||||
|
|
||||||
|
import com.github.benmanes.caffeine.cache.Cache;
|
||||||
|
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||||
|
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @author: ziin
|
||||||
|
* @date: 2025/8/6 20:15
|
||||||
|
*/
|
||||||
|
public class CacheHolder {
|
||||||
|
public static final Cache<String, String> VERIFICATION_MAIL = Caffeine.newBuilder()
|
||||||
|
.expireAfterWrite(5, TimeUnit.MINUTES)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package vvpkassistant.User.controller;
|
package vvpkassistant.User.controller;
|
||||||
import cn.dev33.satoken.stp.StpUtil;
|
import cn.dev33.satoken.stp.StpUtil;
|
||||||
import cn.hutool.core.bean.BeanUtil;
|
import cn.hutool.core.bean.BeanUtil;
|
||||||
|
import cn.hutool.extra.mail.Mail;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import vvpkassistant.CoinRecords.CoinRecords;
|
import vvpkassistant.CoinRecords.CoinRecords;
|
||||||
@@ -397,8 +398,8 @@ public class UserController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/resendMail")
|
@PostMapping("/resendMail")
|
||||||
public ResponseData<Object> resendMail(@RequestBody UserModelDTO userModelDTO){
|
public ResponseData<Object> resendMail(@RequestBody MailModel mailModel){
|
||||||
return ResponseData.success(mailService.resendMail(userModelDTO));
|
return ResponseData.success(mailService.resendMail(mailModel));
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/verificationMail")
|
@GetMapping("/verificationMail")
|
||||||
@@ -406,6 +407,10 @@ public class UserController {
|
|||||||
return ResponseData.success(userService.verificationMail(token));
|
return ResponseData.success(userService.verificationMail(token));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping("/forgetMail")
|
||||||
|
public ResponseData<Object> sendForgetPassWordMail(@RequestBody MailModel mailModel){
|
||||||
|
return ResponseData.success(userService.sendForgetPassWordMail(mailModel));
|
||||||
|
}
|
||||||
|
|
||||||
@GetMapping("/qrcode")
|
@GetMapping("/qrcode")
|
||||||
public ResponseData<Object> generatedQrcode(){
|
public ResponseData<Object> generatedQrcode(){
|
||||||
@@ -428,4 +433,30 @@ public class UserController {
|
|||||||
userService.confirm(scanInfoDTO);
|
userService.confirm(scanInfoDTO);
|
||||||
return ResponseData.success("");
|
return ResponseData.success("");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping("/logout")
|
||||||
|
public ResponseData<Object> logOut(@RequestBody UserModelDTO userModelDTO){
|
||||||
|
userService.logOut(userModelDTO.getId());
|
||||||
|
return ResponseData.success("");
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/setPassword")
|
||||||
|
public ResponseData<Object>setPassWord(@RequestBody UserModelDTO userModelDTO){
|
||||||
|
return ResponseData.success(userService.setPassWord(userModelDTO));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/resetPassword/")
|
||||||
|
public ResponseData<Object>resetPassWord(@RequestBody UserModelDTO userModelDTO){
|
||||||
|
return ResponseData.success(userService.resetPassWord(userModelDTO));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/updateUserMail")
|
||||||
|
public ResponseData<Object>updateUserMail(@RequestBody MailModel mailModel){
|
||||||
|
return ResponseData.success(userService.updateUserMail(mailModel));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/sendUpdateMailConfirmMail")
|
||||||
|
public ResponseData<Object>sendUpdateMailConfirmMail(@RequestBody MailModel mailModel){
|
||||||
|
return ResponseData.success(mailService.sendUpdateConfirmMail(mailModel));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ public class UserModelDTO {
|
|||||||
private Integer inviterId; // 邀请人id
|
private Integer inviterId; // 邀请人id
|
||||||
private String email;
|
private String email;
|
||||||
private String newPassword;
|
private String newPassword;
|
||||||
|
private String confirmPassword;
|
||||||
private String oldPassword;
|
private String oldPassword;
|
||||||
private String password;
|
private String password;
|
||||||
|
private String token;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import vvpkassistant.User.model.DTO.ScanInfoDTO;
|
|||||||
import vvpkassistant.User.model.DTO.UserModelDTO;
|
import vvpkassistant.User.model.DTO.UserModelDTO;
|
||||||
import vvpkassistant.User.model.UserModel;
|
import vvpkassistant.User.model.UserModel;
|
||||||
import vvpkassistant.User.model.UserModelVO;
|
import vvpkassistant.User.model.UserModelVO;
|
||||||
|
import vvpkassistant.mail.model.MailModel;
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -30,4 +30,14 @@ public interface UserService extends IService<UserModel> {
|
|||||||
void scanQrcode(ScanInfoDTO scanInfoDTO);
|
void scanQrcode(ScanInfoDTO scanInfoDTO);
|
||||||
|
|
||||||
void confirm(ScanInfoDTO scanInfoDTO);
|
void confirm(ScanInfoDTO scanInfoDTO);
|
||||||
|
|
||||||
|
void logOut(Integer id);
|
||||||
|
|
||||||
|
boolean setPassWord(UserModelDTO userModelDTO);
|
||||||
|
|
||||||
|
Object sendForgetPassWordMail(MailModel mailModel);
|
||||||
|
|
||||||
|
Object resetPassWord(UserModelDTO userModelDTO);
|
||||||
|
|
||||||
|
Boolean updateUserMail(MailModel mailModel);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,9 +12,11 @@ import com.github.benmanes.caffeine.cache.Caffeine;
|
|||||||
import com.google.zxing.WriterException;
|
import com.google.zxing.WriterException;
|
||||||
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.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import vvpkassistant.Data.WxChatParam;
|
import vvpkassistant.Data.WxChatParam;
|
||||||
import vvpkassistant.Tools.BcryptUtils;
|
import vvpkassistant.Tools.BcryptUtils;
|
||||||
|
import vvpkassistant.Tools.CacheHolder;
|
||||||
import vvpkassistant.Tools.QRCodeUtil;
|
import vvpkassistant.Tools.QRCodeUtil;
|
||||||
import vvpkassistant.Tools.VVTools;
|
import vvpkassistant.Tools.VVTools;
|
||||||
import vvpkassistant.User.mapper.UserDao;
|
import vvpkassistant.User.mapper.UserDao;
|
||||||
@@ -25,6 +27,7 @@ import vvpkassistant.User.model.DTO.UserModelDTO;
|
|||||||
import vvpkassistant.User.model.enumeration.LoginStatusEnum;
|
import vvpkassistant.User.model.enumeration.LoginStatusEnum;
|
||||||
import vvpkassistant.common.ErrorCode;
|
import vvpkassistant.common.ErrorCode;
|
||||||
import vvpkassistant.exception.BusinessException;
|
import vvpkassistant.exception.BusinessException;
|
||||||
|
import vvpkassistant.mail.model.MailModel;
|
||||||
import vvpkassistant.mail.service.MailService;
|
import vvpkassistant.mail.service.MailService;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
@@ -53,6 +56,9 @@ public class UserServiceImpl extends ServiceImpl<UserDao, UserModel> implements
|
|||||||
.expireAfterWrite(2, TimeUnit.MINUTES)
|
.expireAfterWrite(2, TimeUnit.MINUTES)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public UserModelVO loginWithMail(UserModelDTO model) {
|
public UserModelVO loginWithMail(UserModelDTO model) {
|
||||||
|
|
||||||
@@ -99,7 +105,7 @@ public class UserServiceImpl extends ServiceImpl<UserDao, UserModel> implements
|
|||||||
|
|
||||||
// 用户有密码的情况下重新设置密码
|
// 用户有密码的情况下重新设置密码
|
||||||
if (userInfo.getPassword() != null && userModelDTO.getOldPassword() != null) {
|
if (userInfo.getPassword() != null && userModelDTO.getOldPassword() != null) {
|
||||||
if (BcryptUtils.matchPassword(userModelDTO.getOldPassword(), userInfo.getPassword())) {
|
if (BcryptUtils.matchPassword(userInfo.getPassword(),userModelDTO.getOldPassword())) {
|
||||||
userModelDTO.setPassword(BcryptUtils.encryptPassword(userModelDTO.getNewPassword()));
|
userModelDTO.setPassword(BcryptUtils.encryptPassword(userModelDTO.getNewPassword()));
|
||||||
}else {
|
}else {
|
||||||
throw new BusinessException(ErrorCode.PASSWORD_ERROR,"旧密码不正确");
|
throw new BusinessException(ErrorCode.PASSWORD_ERROR,"旧密码不正确");
|
||||||
@@ -150,6 +156,7 @@ public class UserServiceImpl extends ServiceImpl<UserDao, UserModel> implements
|
|||||||
userDao.updateById(oldUser);
|
userDao.updateById(oldUser);
|
||||||
}
|
}
|
||||||
UserModelVO userModelVO = BeanUtil.copyProperties(userModelEntity, UserModelVO.class);
|
UserModelVO userModelVO = BeanUtil.copyProperties(userModelEntity, UserModelVO.class);
|
||||||
|
userModelVO.setHavaPassword(true);
|
||||||
userModelVO.setNewAccount(true);
|
userModelVO.setNewAccount(true);
|
||||||
userModelVO.setChatInfo(wxChatParam);
|
userModelVO.setChatInfo(wxChatParam);
|
||||||
return userModelVO;
|
return userModelVO;
|
||||||
@@ -251,4 +258,77 @@ public class UserServiceImpl extends ServiceImpl<UserDao, UserModel> implements
|
|||||||
}
|
}
|
||||||
log.info("-------确认登录成功uuid:{}-------", scanInfoDTO.getUuid());
|
log.info("-------确认登录成功uuid:{}-------", scanInfoDTO.getUuid());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void logOut(Integer id) {
|
||||||
|
StpUtil.logout(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean setPassWord(UserModelDTO userModelDTO) {
|
||||||
|
UserModel userModel = userDao.selectById(userModelDTO.getId());
|
||||||
|
if (userModel == null) {
|
||||||
|
throw new BusinessException(ErrorCode.USER_DOES_NOT_EXIST);
|
||||||
|
}
|
||||||
|
if (userModel.getPassword()!= null){
|
||||||
|
throw new BusinessException(ErrorCode.SYSTEM_ERROR,"已设置过密码");
|
||||||
|
}
|
||||||
|
if (userModelDTO.getPassword().length()< 6 ){
|
||||||
|
throw new BusinessException(ErrorCode.PARAMS_ERROR,"密码长度不能小于 6 位");
|
||||||
|
}
|
||||||
|
if (!Objects.equals(userModelDTO.getPassword(), userModelDTO.getConfirmPassword())) {
|
||||||
|
log.error("密码{},确认密码{}",userModelDTO.getPassword(),userModelDTO.getConfirmPassword());
|
||||||
|
throw new BusinessException(ErrorCode.PARAMS_ERROR,"两次密码输入不一致");
|
||||||
|
}else{
|
||||||
|
UserModel saveEntity = BeanUtil.copyProperties(userModelDTO, UserModel.class);
|
||||||
|
saveEntity.setPassword(BcryptUtils.encryptPassword(userModelDTO.getPassword()));
|
||||||
|
return userDao.updateById(saveEntity) == 1 ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object sendForgetPassWordMail(MailModel mailModel) {
|
||||||
|
LambdaQueryWrapper<UserModel> lambdaQueryWrapper = new LambdaQueryWrapper<>();
|
||||||
|
UserModel userModel = userDao.selectOne(lambdaQueryWrapper
|
||||||
|
.eq(UserModel::getEmail, mailModel.getMailAddress())
|
||||||
|
.eq(UserModel::getStatus, 0)
|
||||||
|
.eq(UserModel::getMailVerification, 0));
|
||||||
|
if (userModel == null) {
|
||||||
|
throw new BusinessException(ErrorCode.USER_DOES_NOT_EXIST);
|
||||||
|
}
|
||||||
|
|
||||||
|
mailService.sendForgetPassWordMail(mailModel.getMailAddress(),userModel.getId());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object resetPassWord(UserModelDTO userModelDTO) {
|
||||||
|
Integer i = SaTempUtil.parseToken(userModelDTO.getToken(), Integer.class);
|
||||||
|
UserModel userModel = userDao.selectById(i);
|
||||||
|
if (userModel == null) {
|
||||||
|
throw new BusinessException(ErrorCode.USER_DOES_NOT_EXIST);
|
||||||
|
}
|
||||||
|
if (userModelDTO.getPassword().equals(userModelDTO.getConfirmPassword())) {
|
||||||
|
UserModel updateEntity = BeanUtil.copyProperties(userModelDTO, UserModel.class);
|
||||||
|
updateEntity.setPassword(BcryptUtils.encryptPassword(updateEntity.getPassword()));
|
||||||
|
return userDao.updateById(updateEntity) == 1;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Boolean updateUserMail(MailModel mailModel) {
|
||||||
|
String mail = CacheHolder.VERIFICATION_MAIL.getIfPresent(mailModel.getCode());
|
||||||
|
if (mail != null && mail.isEmpty()) {
|
||||||
|
throw new BusinessException(ErrorCode.SYSTEM_ERROR,"验证码过期或验证码错误");
|
||||||
|
}
|
||||||
|
LambdaQueryWrapper<UserModel> lambdaQueryWrapper = new LambdaQueryWrapper<>();
|
||||||
|
UserModel userModel = userDao.selectOne(lambdaQueryWrapper
|
||||||
|
.eq(UserModel::getEmail, mail)
|
||||||
|
.eq(UserModel::getStatus, 0));
|
||||||
|
userModel.setEmail(mailModel.getMailAddress());
|
||||||
|
mailService.sendVerificationMail(mailModel.getMailAddress(),userModel.getId());
|
||||||
|
userModel.setMailVerification(1);
|
||||||
|
return userDao.updateById(userModel) == 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ public class SaTokenConfigure implements WebMvcConfigurer {
|
|||||||
"/user/verificationMail",
|
"/user/verificationMail",
|
||||||
"/user/activate",
|
"/user/activate",
|
||||||
"/user/qrcode",
|
"/user/qrcode",
|
||||||
"/user/check/*",
|
"/user/check/**",
|
||||||
"/user/scan",
|
"/user/scan",
|
||||||
"/user/confirm"
|
"/user/confirm"
|
||||||
|
|
||||||
|
|||||||
@@ -9,5 +9,7 @@ import lombok.Data;
|
|||||||
@Data
|
@Data
|
||||||
public class MailModel {
|
public class MailModel {
|
||||||
private String mailAddress;
|
private String mailAddress;
|
||||||
private Integer code;
|
private Integer userId;
|
||||||
|
private Integer type;
|
||||||
|
private String code;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package vvpkassistant.mail.service;
|
package vvpkassistant.mail.service;
|
||||||
|
|
||||||
import vvpkassistant.User.model.DTO.UserModelDTO;
|
|
||||||
import vvpkassistant.mail.model.MailModel;
|
import vvpkassistant.mail.model.MailModel;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -13,7 +12,9 @@ public interface MailService {
|
|||||||
|
|
||||||
void sendVerificationMail(String emailAddress,Integer userId);
|
void sendVerificationMail(String emailAddress,Integer userId);
|
||||||
|
|
||||||
|
Boolean resendMail(MailModel mailModel);
|
||||||
|
|
||||||
|
void sendForgetPassWordMail(String mailAddress, Integer id);
|
||||||
|
|
||||||
Boolean resendMail(UserModelDTO userModelDTO);
|
Object sendUpdateConfirmMail(MailModel mailModel);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,23 @@
|
|||||||
package vvpkassistant.mail.service;
|
package vvpkassistant.mail.service;
|
||||||
|
|
||||||
import cn.dev33.satoken.temp.SaTempUtil;
|
import cn.dev33.satoken.temp.SaTempUtil;
|
||||||
|
import cn.hutool.core.util.RandomUtil;
|
||||||
import cn.hutool.extra.mail.MailUtil;
|
import cn.hutool.extra.mail.MailUtil;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.github.benmanes.caffeine.cache.Cache;
|
import com.github.benmanes.caffeine.cache.Cache;
|
||||||
import com.github.benmanes.caffeine.cache.Caffeine;
|
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.scheduling.annotation.Async;
|
import org.springframework.scheduling.annotation.Async;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import vvpkassistant.User.model.DTO.UserModelDTO;
|
import vvpkassistant.Tools.CacheHolder;
|
||||||
|
import vvpkassistant.User.mapper.UserDao;
|
||||||
|
import vvpkassistant.User.model.UserModel;
|
||||||
import vvpkassistant.common.ErrorCode;
|
import vvpkassistant.common.ErrorCode;
|
||||||
import vvpkassistant.exception.BusinessException;
|
import vvpkassistant.exception.BusinessException;
|
||||||
|
import vvpkassistant.mail.model.MailModel;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -29,8 +35,15 @@ public class MailServiceImpl implements MailService {
|
|||||||
@Value("${verificationMailUrl}")
|
@Value("${verificationMailUrl}")
|
||||||
private String verificationMailUrl;
|
private String verificationMailUrl;
|
||||||
|
|
||||||
|
@Value("${forgetPassWordUrl}")
|
||||||
|
private String forgetPassWordUrl;
|
||||||
|
|
||||||
private final Cache<String, Object> emailSendCache = Caffeine.newBuilder()
|
|
||||||
|
@Resource
|
||||||
|
private UserDao userDao;
|
||||||
|
|
||||||
|
|
||||||
|
private static final Cache<String, Object> emailSendCache = Caffeine.newBuilder()
|
||||||
.expireAfterWrite(1, TimeUnit.MINUTES)
|
.expireAfterWrite(1, TimeUnit.MINUTES)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
@@ -365,12 +378,217 @@ public class MailServiceImpl implements MailService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Boolean resendMail(UserModelDTO userModelDTO) {
|
public Boolean resendMail(MailModel mailModel) {
|
||||||
try {
|
Object ifPresent = emailSendCache.getIfPresent(mailModel.getMailAddress());
|
||||||
sendMail(userModelDTO.getEmail(), userModelDTO.getId());
|
if (ifPresent == null) {
|
||||||
|
switch (mailModel.getType()) {
|
||||||
|
case 1:
|
||||||
|
sendMail(mailModel.getMailAddress(), mailModel.getUserId());
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
sendVerificationMail(mailModel.getMailAddress(), mailModel.getUserId());
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
sendForgetPassWordMail(mailModel.getMailAddress(), mailModel.getUserId());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}else {
|
||||||
|
throw new BusinessException(ErrorCode.EMAIL_SEND_FREQUENT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendForgetPassWordMail(String mailAddress, Integer userId) {
|
||||||
|
if (checkCache(mailAddress)){
|
||||||
|
String token = SaTempUtil.createToken(userId, 600);
|
||||||
|
MailUtil.send(mailAddress, "验证你的邮箱", "<!DOCTYPE html>\n" +
|
||||||
|
"<html lang=\"en\">\n" +
|
||||||
|
"<head>\n" +
|
||||||
|
" <meta charset=\"UTF-8\">\n" +
|
||||||
|
" <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n" +
|
||||||
|
" <title>Account Activation</title>\n" +
|
||||||
|
" <style>\n" +
|
||||||
|
" * {\n" +
|
||||||
|
" margin: 0;\n" +
|
||||||
|
" padding: 0;\n" +
|
||||||
|
" box-sizing: border-box;\n" +
|
||||||
|
" }\n" +
|
||||||
|
"\n" +
|
||||||
|
" body {\n" +
|
||||||
|
" font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;\n" +
|
||||||
|
" background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n" +
|
||||||
|
" min-height: 100vh;\n" +
|
||||||
|
" display: flex;\n" +
|
||||||
|
" align-items: center;\n" +
|
||||||
|
" justify-content: center;\n" +
|
||||||
|
" padding: 20px;\n" +
|
||||||
|
" }\n" +
|
||||||
|
"\n" +
|
||||||
|
" .container {\n" +
|
||||||
|
" background: white;\n" +
|
||||||
|
" border-radius: 12px;\n" +
|
||||||
|
" box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);\n" +
|
||||||
|
" padding: 40px;\n" +
|
||||||
|
" text-align: center;\n" +
|
||||||
|
" max-width: 400px;\n" +
|
||||||
|
" width: 100%;\n" +
|
||||||
|
" }\n" +
|
||||||
|
"\n" +
|
||||||
|
" .icon {\n" +
|
||||||
|
" width: 60px;\n" +
|
||||||
|
" height: 60px;\n" +
|
||||||
|
" background: #4CAF50;\n" +
|
||||||
|
" border-radius: 50%;\n" +
|
||||||
|
" display: flex;\n" +
|
||||||
|
" align-items: center;\n" +
|
||||||
|
" justify-content: center;\n" +
|
||||||
|
" margin: 0 auto 20px;\n" +
|
||||||
|
" color: white;\n" +
|
||||||
|
" font-size: 24px;\n" +
|
||||||
|
" }\n" +
|
||||||
|
"\n" +
|
||||||
|
" h1 {\n" +
|
||||||
|
" color: #333;\n" +
|
||||||
|
" font-size: 24px;\n" +
|
||||||
|
" margin-bottom: 10px;\n" +
|
||||||
|
" font-weight: 600;\n" +
|
||||||
|
" }\n" +
|
||||||
|
"\n" +
|
||||||
|
" .subtitle {\n" +
|
||||||
|
" color: #666;\n" +
|
||||||
|
" font-size: 16px;\n" +
|
||||||
|
" margin-bottom: 30px;\n" +
|
||||||
|
" line-height: 1.5;\n" +
|
||||||
|
" }\n" +
|
||||||
|
"\n" +
|
||||||
|
" .activate-button {\n" +
|
||||||
|
" display: inline-block;\n" +
|
||||||
|
" background: #4CAF50;\n" +
|
||||||
|
" border: none;\n" +
|
||||||
|
" border-radius: 8px;\n" +
|
||||||
|
" padding: 15px 30px;\n" +
|
||||||
|
" margin: 20px 0;\n" +
|
||||||
|
" font-size: 18px;\n" +
|
||||||
|
" font-weight: bold;\n" +
|
||||||
|
" color: white;\n" +
|
||||||
|
" text-decoration: none;\n" +
|
||||||
|
" cursor: pointer;\n" +
|
||||||
|
" transition: all 0.3s ease;\n" +
|
||||||
|
" box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);\n" +
|
||||||
|
" }\n" +
|
||||||
|
" \n" +
|
||||||
|
" .activate-button:hover {\n" +
|
||||||
|
" background: #45a049;\n" +
|
||||||
|
" transform: translateY(-2px);\n" +
|
||||||
|
" box-shadow: 0 6px 8px rgba(0, 0, 0, 0.15);\n" +
|
||||||
|
" }\n" +
|
||||||
|
" \n" +
|
||||||
|
" .activate-button:active {\n" +
|
||||||
|
" transform: translateY(0);\n" +
|
||||||
|
" box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);\n" +
|
||||||
|
" }\n" +
|
||||||
|
"\n" +
|
||||||
|
" .info {\n" +
|
||||||
|
" background: #e3f2fd;\n" +
|
||||||
|
" border-left: 4px solid #2196F3;\n" +
|
||||||
|
" padding: 15px;\n" +
|
||||||
|
" margin: 20px 0;\n" +
|
||||||
|
" text-align: left;\n" +
|
||||||
|
" border-radius: 4px;\n" +
|
||||||
|
" }\n" +
|
||||||
|
"\n" +
|
||||||
|
" .info-title {\n" +
|
||||||
|
" font-weight: 600;\n" +
|
||||||
|
" color: #1976D2;\n" +
|
||||||
|
" margin-bottom: 5px;\n" +
|
||||||
|
" }\n" +
|
||||||
|
"\n" +
|
||||||
|
" .info-text {\n" +
|
||||||
|
" color: #424242;\n" +
|
||||||
|
" font-size: 14px;\n" +
|
||||||
|
" line-height: 1.4;\n" +
|
||||||
|
" }\n" +
|
||||||
|
"\n" +
|
||||||
|
" .footer {\n" +
|
||||||
|
" margin-top: 30px;\n" +
|
||||||
|
" padding-top: 20px;\n" +
|
||||||
|
" border-top: 1px solid #eee;\n" +
|
||||||
|
" color: #999;\n" +
|
||||||
|
" font-size: 12px;\n" +
|
||||||
|
" }\n" +
|
||||||
|
"\n" +
|
||||||
|
" @media (max-width: 480px) {\n" +
|
||||||
|
" .container {\n" +
|
||||||
|
" padding: 30px 20px;\n" +
|
||||||
|
" }\n" +
|
||||||
|
" \n" +
|
||||||
|
" .verification-code {\n" +
|
||||||
|
" font-size: 24px;\n" +
|
||||||
|
" letter-spacing: 2px;\n" +
|
||||||
|
" }\n" +
|
||||||
|
" }\n" +
|
||||||
|
" </style>\n" +
|
||||||
|
"</head>\n" +
|
||||||
|
"<body>\n" +
|
||||||
|
" <div class=\"container\">\n" +
|
||||||
|
" <div class=\"icon\">✉</div>\n" +
|
||||||
|
" \n" +
|
||||||
|
" <h1>Verification Mail</h1>\n" +
|
||||||
|
" <p class=\"subtitle\">Please click the button below to reset your password</p>\n" +
|
||||||
|
" \n" +
|
||||||
|
" <a href=\""+ forgetPassWordUrl + token + "\" class=\"activate-button\">\n" +
|
||||||
|
" Reset PassWord\n" +
|
||||||
|
" </a>\n" +
|
||||||
|
" \n" +
|
||||||
|
" <div class=\"info\">\n" +
|
||||||
|
" <div class=\"info-title\">Important Notice:</div>\n" +
|
||||||
|
" <div class=\"info-text\">\n" +
|
||||||
|
" • This activation link is valid for 10 minutes<br>\n" +
|
||||||
|
" • Please do not share this link with anyone<br>\n" +
|
||||||
|
" • If you didn't register an account, please ignore this message\n" +
|
||||||
|
" </div>\n" +
|
||||||
|
" </div>\n" +
|
||||||
|
" \n" +
|
||||||
|
" <div class=\"footer\">\n" +
|
||||||
|
" This is an automated message. Please do not reply to this email.\n" +
|
||||||
|
" </div>\n" +
|
||||||
|
" </div>\n" +
|
||||||
|
"</body>\n" +
|
||||||
|
"</html>\n", true);
|
||||||
|
emailSendCache.put(mailAddress, userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object sendUpdateConfirmMail(MailModel mailModel) {
|
||||||
|
LambdaQueryWrapper<UserModel> lambdaQueryWrapper = new LambdaQueryWrapper<>();
|
||||||
|
UserModel userModel = userDao.selectOne(
|
||||||
|
lambdaQueryWrapper.eq(UserModel::getEmail, mailModel.getMailAddress())
|
||||||
|
.eq(UserModel::getStatus, 0)
|
||||||
|
.eq(UserModel::getMailVerification, 0));
|
||||||
|
if (userModel == null){
|
||||||
|
throw new BusinessException(ErrorCode.USER_DOES_NOT_EXIST);
|
||||||
|
}
|
||||||
|
if (checkCache(mailModel.getMailAddress())) {
|
||||||
|
String code = RandomUtil.randomString(6);
|
||||||
|
emailSendCache.put(mailModel.getMailAddress(), code);
|
||||||
|
CacheHolder.VERIFICATION_MAIL.put(code, mailModel.getMailAddress());
|
||||||
|
MailUtil.send(mailModel.getMailAddress(),"your Verification code is :" + code,
|
||||||
|
"your Verification code is :" + code,false);
|
||||||
|
log.info("sendMailto:{},Verification code is :{}", mailModel.getMailAddress(),code);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public Boolean checkCache(String mailAddress){
|
||||||
|
Object ifPresent = emailSendCache.getIfPresent(mailAddress);
|
||||||
|
if (ifPresent == null) {
|
||||||
return true;
|
return true;
|
||||||
}catch (Exception e){
|
}else {
|
||||||
throw new BusinessException(ErrorCode.SYSTEM_ERROR,e.getMessage());
|
throw new BusinessException(ErrorCode.EMAIL_SEND_FREQUENT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,3 +44,4 @@ sa-token:
|
|||||||
|
|
||||||
activateUrl: http://192.168.1.174:8086/user/activate?token=
|
activateUrl: http://192.168.1.174:8086/user/activate?token=
|
||||||
verificationMailUrl: http://192.168.1.174:8086/user/verification?token=
|
verificationMailUrl: http://192.168.1.174:8086/user/verification?token=
|
||||||
|
forgetPassWordUrl: http://192.168.1.174:8086/user//resetPassword/?token=
|
||||||
@@ -3,8 +3,8 @@ host = smtp.exmail.qq.com
|
|||||||
# 邮件服务器的SMTP端口,可选,默认25
|
# 邮件服务器的SMTP端口,可选,默认25
|
||||||
port = 465
|
port = 465
|
||||||
# 发件人(必须正确,否则发送失败)
|
# 发件人(必须正确,否则发送失败)
|
||||||
from = chenfu@bilibili.so
|
from = niuyuxi@hanxiaokj.cn
|
||||||
# 用户名,默认为发件人邮箱前缀
|
# 用户名,默认为发件人邮箱前缀
|
||||||
user = chenfu@bilibili.so
|
user = niuyuxi@hanxiaokj.cn
|
||||||
pass = Yt7rWTizdAvE4dc7
|
pass = tF35umug9CBCBKqR
|
||||||
sslEnable = true
|
sslEnable = true
|
||||||
@@ -44,3 +44,4 @@ sa-token:
|
|||||||
|
|
||||||
activateUrl: http://192.168.1.174:8086/user/activate?token=
|
activateUrl: http://192.168.1.174:8086/user/activate?token=
|
||||||
verificationMailUrl: http://192.168.1.174:8086/user/verification?token=
|
verificationMailUrl: http://192.168.1.174:8086/user/verification?token=
|
||||||
|
forgetPassWordUrl: http://192.168.1.174:8086/user//resetPassword/?token=
|
||||||
Reference in New Issue
Block a user