diff --git a/unilife-server/pom.xml b/unilife-server/pom.xml
index 99ffc1d..254efa2 100644
--- a/unilife-server/pom.xml
+++ b/unilife-server/pom.xml
@@ -49,6 +49,12 @@
hutool-all
5.8.16
+
+
+
+ org.springframework.boot
+ spring-boot-starter-data-redis
+
org.springframework.boot
diff --git a/unilife-server/src/main/java/com/unilife/common/constant/RedisConstant.java b/unilife-server/src/main/java/com/unilife/common/constant/RedisConstant.java
new file mode 100644
index 0000000..6118e4c
--- /dev/null
+++ b/unilife-server/src/main/java/com/unilife/common/constant/RedisConstant.java
@@ -0,0 +1,7 @@
+package com.unilife.common.constant;
+
+
+public class RedisConstant {
+ public static final String LOGIN_EMAIL_KEY="login:email:";
+ public static final String LOGIN_EMAIL_LIMIT_KEY = "login:email:limit:";
+}
diff --git a/unilife-server/src/main/java/com/unilife/controller/UserController.java b/unilife-server/src/main/java/com/unilife/controller/UserController.java
index 8ea9ad6..0a28a1e 100644
--- a/unilife-server/src/main/java/com/unilife/controller/UserController.java
+++ b/unilife-server/src/main/java/com/unilife/controller/UserController.java
@@ -4,6 +4,7 @@ import com.unilife.common.result.Result;
import com.unilife.model.dto.EmailDTO;
import com.unilife.model.dto.LogDTO;
import com.unilife.model.dto.LoginDTO;
+import com.unilife.model.dto.LoginEmailDTO;
import com.unilife.service.UserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
@@ -42,5 +43,10 @@ public class UserController {
return userService.sendVerificationCode(email);
}
+ @ApiOperation(value = "邮箱验证码登录")
+ @PostMapping("login/code")
+ public Result loginWithEmailCode(@RequestBody LoginEmailDTO loginEmailDTO){
+ return userService.loginWithEmail(loginEmailDTO);
+ }
}
diff --git a/unilife-server/src/main/java/com/unilife/mapper/UserMapper.java b/unilife-server/src/main/java/com/unilife/mapper/UserMapper.java
index 4e4d997..9520351 100644
--- a/unilife-server/src/main/java/com/unilife/mapper/UserMapper.java
+++ b/unilife-server/src/main/java/com/unilife/mapper/UserMapper.java
@@ -8,4 +8,5 @@ import org.apache.ibatis.annotations.Param;
public interface UserMapper {
void insert(User user);
User FindByEmail(@Param("email") String email, @Param("password") String password);
+ User getUserByEmail(String email);
}
diff --git a/unilife-server/src/main/java/com/unilife/model/dto/LoginEmailDTO.java b/unilife-server/src/main/java/com/unilife/model/dto/LoginEmailDTO.java
new file mode 100644
index 0000000..cd53e67
--- /dev/null
+++ b/unilife-server/src/main/java/com/unilife/model/dto/LoginEmailDTO.java
@@ -0,0 +1,13 @@
+package com.unilife.model.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class LoginEmailDTO {
+ private String email;
+ private String code;
+}
diff --git a/unilife-server/src/main/java/com/unilife/service/UserService.java b/unilife-server/src/main/java/com/unilife/service/UserService.java
index 2e693d7..fece724 100644
--- a/unilife-server/src/main/java/com/unilife/service/UserService.java
+++ b/unilife-server/src/main/java/com/unilife/service/UserService.java
@@ -3,7 +3,7 @@ package com.unilife.service;
import com.unilife.common.result.Result;
import com.unilife.model.dto.LogDTO;
import com.unilife.model.dto.LoginDTO;
-import com.unilife.model.entity.User;
+import com.unilife.model.dto.LoginEmailDTO;
public interface UserService {
@@ -11,4 +11,8 @@ public interface UserService {
Result login(LogDTO logDTO);
Result sendVerificationCode(String email);
+
+ Result loginWithEmail(LoginEmailDTO loginEmailDTO);
+
+
}
diff --git a/unilife-server/src/main/java/com/unilife/service/impl/UserServiceImpl.java b/unilife-server/src/main/java/com/unilife/service/impl/UserServiceImpl.java
index 2d40a17..29ca4ad 100644
--- a/unilife-server/src/main/java/com/unilife/service/impl/UserServiceImpl.java
+++ b/unilife-server/src/main/java/com/unilife/service/impl/UserServiceImpl.java
@@ -2,10 +2,13 @@ package com.unilife.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.RandomUtil;
+import cn.hutool.core.util.StrUtil;
+import com.unilife.common.constant.RedisConstant;
import com.unilife.common.result.Result;
import com.unilife.mapper.UserMapper;
import com.unilife.model.dto.LogDTO;
import com.unilife.model.dto.LoginDTO;
+import com.unilife.model.dto.LoginEmailDTO;
import com.unilife.model.entity.User;
import com.unilife.model.vo.LogVO;
import com.unilife.model.vo.LoginVO;
@@ -14,6 +17,7 @@ import com.unilife.utils.RegexUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
+import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Component;
@@ -22,6 +26,13 @@ import org.springframework.stereotype.Service;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
+import java.time.Duration;
+import java.time.LocalDateTime;
+import java.util.HashMap;
+import java.util.Map;
+
+import static com.unilife.common.constant.RedisConstant.LOGIN_EMAIL_KEY;
+
@Slf4j
@Component
@Service
@@ -33,9 +44,15 @@ public class UserServiceImpl implements UserService {
@Autowired
private JavaMailSender mailSender;
+ @Autowired
+ private StringRedisTemplate stringRedisTemplate;
+
@Value("${spring.mail.username}")
private String from;
+ final int CODE_EXPIRE_MINUTES = 10;
+ final int LIMIT_SECONDS=60;
+
@Override
@@ -76,14 +93,25 @@ public class UserServiceImpl implements UserService {
return Result.error(400,"邮箱格式不正确");
}
- //2.生成随机验证码
- String code = RandomUtil.randomNumbers(6);
- log.debug("成功生成验证码,邮箱{},验证码{}", email, code);
+ //2.防止频繁发送验证码
+ String countKey = RedisConstant.LOGIN_EMAIL_LIMIT_KEY + email;
+ Boolean setSuccess = stringRedisTemplate.opsForValue().setIfAbsent(
+ countKey,
+ "1",
+ Duration.ofSeconds(LIMIT_SECONDS)
+ );
+
+ if (Boolean.FALSE.equals(setSuccess)) {
+ return Result.error(null, "请求过于频繁,请稍后再试");
+ }
+ //3.生成随机验证码
+ String code = RandomUtil.randomNumbers(6);
+ log.debug("成功生成验证码,邮箱{},验证码{}", email, code);
- //3.发送验证码到邮箱
+ //4.发送验证码到邮箱
try {
//构建邮件
MimeMessage message=mailSender.createMimeMessage();
@@ -115,12 +143,78 @@ public class UserServiceImpl implements UserService {
}
- //4.存储随机产生的验证码
+ //5.存储随机产生的验证码,设置有效期为十分钟
+ stringRedisTemplate.opsForValue().set(LOGIN_EMAIL_KEY + email, code, Duration.ofMinutes(CODE_EXPIRE_MINUTES));
+
+ return Result.success(200,"验证码已发送");
+ }
+
+ @Override
+ public Result loginWithEmail(LoginEmailDTO loginEmailDTO) {
+ String email=loginEmailDTO.getEmail();
+
+ if(RegexUtils.isEmailInvalid(email)){
+ return Result.error(null,"请输入正确的邮箱");
+ }
+
+ String cacheCode = stringRedisTemplate.opsForValue().get(RedisConstant.LOGIN_EMAIL_KEY + email);
+ if (cacheCode == null) {
+ return Result.error(null, "验证码已过期或未发送,请重新获取");
+ }
+
+ // 3. 校验验证码是否正确
+ String code = loginEmailDTO.getCode();
+ if (!cacheCode.equals(code)) {
+ return Result.error(null, "验证码错误");
+ }
+
+ // 4. 验证通过,删除验证码
+ stringRedisTemplate.delete(RedisConstant.LOGIN_EMAIL_KEY + email);
+
+ // 5. 查询用户是否存在
+ User user=userMapper.getUserByEmail(email);
+ if(user == null){
+ user=createUserWithEmail(email);
+ }
+
+ //6.生成登录凭证
//TODO
+ // 8. 返回用户信息和登录凭证
+ Map userInfo = new HashMap<>();
+ //HashMap userInfo.put("token", token);
+ userInfo.put("user", user);
- return Result.success(200,"验证码已发送");
+ return Result.success(userInfo);
+ }
+
+ /**
+ * 使用邮箱信息创建新用户
+ */
+ private User createUserWithEmail(String email) {
+ User user = new User();
+ user.setEmail(email);
+ user.setNickname("用户" + RandomUtil.randomString(6)); // 生成随机昵称
+ String username = email.split("@")[0]+"_"+ RandomUtil.randomString(4); // 使用@前面的部分作为用户名
+ user.setUsername(username);
+
+ String password=RandomUtil.randomString(6);
+ user.setPassword(password);
+ user.setRole((byte)0); // 普通用户角色
+ user.setStatus((byte)1); // 正常状态
+ user.setIsVerified((byte)0); // 未验证
+ user.setPoints(0); // 初始积分
+ user.setGender((byte)0);
+ // 保存用户
+ try {
+ userMapper.insert(user);
+ }catch (Exception e){
+ log.error("用户创建失败");
+ }
+
+ return user;
}
+
}
diff --git a/unilife-server/src/main/resources/application.yml b/unilife-server/src/main/resources/application.yml
index 17b36cb..3986424 100644
--- a/unilife-server/src/main/resources/application.yml
+++ b/unilife-server/src/main/resources/application.yml
@@ -20,6 +20,9 @@ spring:
socketFactory:
port: 465
class: javax.net.ssl.SSLSocketFactory
+ redis:
+ host: 127.0.0.1
+ port: 6379
knife4j:
enable: true
openapi:
@@ -44,4 +47,4 @@ mybatis:
map-underscore-to-camel-case: true
logging:
level:
- com.unilife: debug
+ com.unilife: debug
\ No newline at end of file
diff --git a/unilife-server/src/main/resources/mappers/UserMapper.xml b/unilife-server/src/main/resources/mappers/UserMapper.xml
index 20a789b..e422367 100644
--- a/unilife-server/src/main/resources/mappers/UserMapper.xml
+++ b/unilife-server/src/main/resources/mappers/UserMapper.xml
@@ -14,23 +14,7 @@
INSERT INTO users (
- username,
- email,
- password,
- nickname,
- avatar,
- bio,
- gender,
- student_id,
- department,
- major,
- grade,
- points,
- role,
- status,
- is_verified,
- login_ip,
- login_time
+ username, email, password,nickname,avatar,bio, gender,student_id,department, major,grade,points,role,status,is_verified,login_ip,login_time
) VALUES (
#{username},
#{email},
@@ -57,4 +41,25 @@
FROM users
WHERE email = #{email} AND password = #{password}
+
+
\ No newline at end of file