验证码发送
This commit is contained in:
parent
fea726f2ed
commit
89fdab1864
8
pom.xml
8
pom.xml
|
@ -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>
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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]
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue