验证码发送

This commit is contained in:
Amadeus 2024-05-11 23:07:13 +08:00
parent fea726f2ed
commit 89fdab1864
10 changed files with 176 additions and 29 deletions

View File

@ -66,6 +66,14 @@
<artifactId>java-jwt</artifactId> <artifactId>java-jwt</artifactId>
<version>4.3.0</version> <version>4.3.0</version>
</dependency> </dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<dependency> <dependency>
<groupId>org.springframework.security</groupId> <groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId> <artifactId>spring-security-test</artifactId>

View File

@ -0,0 +1,18 @@
package com.example.config;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.core.QueueBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RabbitConfiguration {
@Bean("emailQueue")
public Queue emailQueue(){
return QueueBuilder
.durable("mail")
.build();
}
}

View File

@ -0,0 +1,26 @@
package com.example.controller;
import com.example.entity.RestBean;
import com.example.service.AccountService;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api/auth")
public class AuthorizeController {
@Resource
AccountService service;
@GetMapping("/ask-code")
public RestBean<Void> askVerifyCode(@RequestParam String email,
@RequestParam String type ,
HttpServletRequest request){
String message = service.registerEmailVerityCode(type , email , request.getRemoteAddr());
return message == null ? RestBean.success() : RestBean.failure(400 , message);
}
}

View File

@ -1,29 +0,0 @@
version: '3'
services:
nginx:
image: nginx
ports:
- 8888:80
deploy:
mode: replicated
replicas: 3
visualizer:
image: dockersamples/visualizer
ports:
- 8080:8080
volumes:
- /var/run/docker.sock:/var/run/docker.sock
deploy:
replicas: 1
placement:
constraints: [node.repo == manager]
portainer:
image: portainer/portainer
ports:
- 9000:9000
volumes:
- /var/run/docker.sock:/var/run/docker.sock
deploy:
replicas: 1
placement:
constraints: [node.role == manager]

View File

@ -0,0 +1,46 @@
package com.example.listener;
import jakarta.annotation.Resource;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.stereotype.Component;
import java.util.Map;
@Component
@RabbitListener(queues = "mail")
public class MailQueueListener {
@Resource
JavaMailSender sender;
@Value("${spring.mail.username}")
String username;
@RabbitHandler
public void sendMailMessage(Map<String , Object> data){
String email = (String) data.get("email");
Integer code = (Integer) data.get("code");
String type = (String) data.get("type");
SimpleMailMessage message = switch (type) {
case "register" -> createMessage("欢迎注册我们的网站" ,
"您的邮件注册验证码为:" + code + ",有效时间三分钟,为了保障您的安全 , 请勿向他人泄漏验证码信息.", email);
case "reset" -> createMessage("你的密码重置邮件" ,
"你好,您正在进行重置密码操作,验证码:" + code + ", 有效时间三分钟,如非本人操作,请无视." ,email);
default -> null;
};
if (message == null) return;
sender.send(message);
}
private SimpleMailMessage createMessage(String title , String content , String email){
SimpleMailMessage message = new SimpleMailMessage();
message.setSubject(title);
message.setText(content);
message.setTo(email);
message.setFrom(username);
return message;
}
}

View File

@ -7,4 +7,5 @@ import org.springframework.security.core.userdetails.UserDetailsService;
public interface AccountService extends IService<Account> , UserDetailsService { public interface AccountService extends IService<Account> , UserDetailsService {
public Account findAccountByNameOrEmail(String text); public Account findAccountByNameOrEmail(String text);
String registerEmailVerityCode(String type , String email , String ip);
} }

View File

@ -4,14 +4,32 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.entity.dto.Account; import com.example.entity.dto.Account;
import com.example.mapper.AccountMapper; import com.example.mapper.AccountMapper;
import com.example.service.AccountService; import com.example.service.AccountService;
import com.example.utils.Const;
import com.example.utils.FlowUtils;
import jakarta.annotation.Resource;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.Map;
import java.util.Objects;
import java.util.Random;
import java.util.concurrent.TimeUnit;
@Service @Service
public class AccountServiceImpl extends ServiceImpl<AccountMapper , Account> implements AccountService { public class AccountServiceImpl extends ServiceImpl<AccountMapper , Account> implements AccountService {
@Resource
FlowUtils utils;
@Resource
AmqpTemplate amqpTemplate;
@Resource
StringRedisTemplate stringRedisTemplate;
@Override @Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
Account account = this.findAccountByNameOrEmail(username); Account account = this.findAccountByNameOrEmail(username);
@ -24,10 +42,34 @@ public class AccountServiceImpl extends ServiceImpl<AccountMapper , Account> imp
.build(); .build();
} }
@Override
public String registerEmailVerityCode(String type, String email, String ip) {
synchronized (ip.intern()){
if (this.verifyLimit(ip)){
return "请求频繁,请稍后再试";
}
Random random = new Random();
int code = random.nextInt(899999) + 100000;
Map<String , Object> data = Map.of("type" , type , "email", email , "code" , code);
amqpTemplate.convertAndSend("mail" , data);
stringRedisTemplate.opsForValue()
.set(Const.VERIFY_EMAIL_DATA + email ,String.valueOf(code), 3 , TimeUnit.MINUTES );
return null;
}
}
public Account findAccountByNameOrEmail(String text){ public Account findAccountByNameOrEmail(String text){
return this.query() return this.query()
.eq("username",text).or() .eq("username",text).or()
.eq("email",text) .eq("email",text)
.one(); .one();
} }
private boolean verifyLimit(String ip){
String key = Const.VERIFY_EMAIL_LIMIT + ip;
return utils.limitOnceCheck(key , 60);
}
} }

View File

@ -3,6 +3,9 @@ package com.example.utils;
public class Const { public class Const {
public static final String JWT_BLACK_LIST = "jwt:blacklist:"; public static final String JWT_BLACK_LIST = "jwt:blacklist:";
public static final String VERIFY_EMAIL_LIMIT = "verify:email:limit:";
public static final String VERIFY_EMAIL_DATA = "verify:email:data:";
public static final int ORDER_CORS = -102; public static final int ORDER_CORS = -102;
} }

View File

@ -0,0 +1,22 @@
package com.example.utils;
import jakarta.annotation.Resource;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;
@Component
public class FlowUtils {
@Resource
StringRedisTemplate template;
public boolean limitOnceCheck(String key , int blockTime){
if (Boolean.TRUE.equals(template.hasKey(key))){
return false;
}else {
template.opsForValue().set(key , "" , blockTime , TimeUnit.SECONDS);
return true;
}
}
}

View File

@ -1,5 +1,15 @@
spring: spring:
mail:
host: smtp.163.com
username: realmeamadeus@163.com
password: SFTIRQAPGTZJFEPY
rabbitmq:
addresses: 8.138.140.94
username: rabbitmq
password: rabbitmq_Ek=hv-W0
virtual-host: /
port: 5672
security: security:
filter: filter:
order: -100 #默认值为-100 order: -100 #默认值为-100