package me.zhengjie.system.domain; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import org.hibernate.annotations.CreationTimestamp; import javax.persistence.*; import javax.validation.constraints.NotBlank; import java.sql.Timestamp; /** * @author jie * @date 2018-12-26 */ @Data @Entity @AllArgsConstructor @NoArgsConstructor @Table(name = "verification_code") public class VerificationCode { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String code; /** * 使用场景,自己定义 */ private String scenes; /** * true 为有效,false 为无效,验证时状态+时间+具体的邮箱或者手机号 */ private Boolean status = true; /** * 类型 :phone 和 email */ @NotBlank private String type; /** * 具体的phone与email */ @NotBlank private String value; /** * 创建日期 */ @CreationTimestamp private Timestamp createTime; public VerificationCode(String code, String scenes, @NotBlank String type, @NotBlank String value) { this.code = code; this.scenes = scenes; this.type = type; this.value = value; } }
package me.zhengjie.system.rest; import me.zhengjie.common.utils.ElAdminConstant; import me.zhengjie.common.utils.RequestHolder; import me.zhengjie.core.security.JwtUser; import me.zhengjie.core.utils.JwtTokenUtil; import me.zhengjie.system.domain.VerificationCode; import me.zhengjie.system.service.VerificationCodeService; import me.zhengjie.tools.domain.vo.EmailVo; import me.zhengjie.tools.service.EmailService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.web.bind.annotation.*; /** * @author jie * @date 2018-12-26 */ @RestController @RequestMapping("api") public class VerificationCodeController { @Autowired private VerificationCodeService verificationCodeService; @Autowired private JwtTokenUtil jwtTokenUtil; @Autowired @Qualifier("jwtUserDetailsService") private UserDetailsService userDetailsService; @Autowired private EmailService emailService; @PostMapping(value = "/code/resetEmail") public ResponseEntity resetEmail(@RequestBody VerificationCode code) throws Exception { code.setScenes(ElAdminConstant.RESET_MAIL); EmailVo emailVo = verificationCodeService.sendEmail(code); emailService.send(emailVo,emailService.find()); return new ResponseEntity(HttpStatus.OK); } @PostMapping(value = "/code/email/resetPass") public ResponseEntity resetPass() throws Exception { JwtUser jwtUser = (JwtUser)userDetailsService.loadUserByUsername(jwtTokenUtil.getUserName(RequestHolder.getHttpServletRequest())); VerificationCode code = new VerificationCode(); code.setType("email"); code.setValue(jwtUser.getEmail()); code.setScenes(ElAdminConstant.RESET_MAIL); EmailVo emailVo = verificationCodeService.sendEmail(code); emailService.send(emailVo,emailService.find()); return new ResponseEntity(HttpStatus.OK); } @GetMapping(value = "/code/validated") public ResponseEntity validated(VerificationCode code){ verificationCodeService.validated(code); return new ResponseEntity(HttpStatus.OK); } }
package me.zhengjie.system.service; import me.zhengjie.system.domain.VerificationCode; import me.zhengjie.tools.domain.vo.EmailVo; /** * @author jie * @date 2018-12-26 */ public interface VerificationCodeService { /** * 发送邮件验证码 * @param code */ EmailVo sendEmail(VerificationCode code); /** * 验证 * @param code */ void validated(VerificationCode code); }
package me.zhengjie.system.service.impl; import cn.hutool.core.util.RandomUtil; import me.zhengjie.common.exception.BadRequestException; import me.zhengjie.common.utils.ElAdminConstant; import me.zhengjie.system.domain.VerificationCode; import me.zhengjie.system.repository.VerificationCodeRepository; import me.zhengjie.system.service.VerificationCodeService; import me.zhengjie.tools.domain.vo.EmailVo; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import java.util.Arrays; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; /** * @author jie * @date 2018-12-26 */ @Service @Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class) public class VerificationCodeServiceImpl implements VerificationCodeService { @Autowired private VerificationCodeRepository verificationCodeRepository; @Value("${code.expiration}") private Integer expiration; @Override @Transactional(rollbackFor = Exception.class) public EmailVo sendEmail(VerificationCode code) { EmailVo emailVo = null; String content = ""; VerificationCode verificationCode = verificationCodeRepository.findByScenesAndTypeAndValueAndStatusIsTrue(code.getScenes(),code.getType(),code.getValue()); // 如果不存在有效的验证码,就创建一个新的 if(verificationCode == null){ code.setCode(RandomUtil.randomNumbers (6)); content = ElAdminConstant.EMAIL_CODE + code.getCode() + "</p>"; emailVo = new EmailVo(Arrays.asList(code.getValue()),"eladmin后台管理系统",content); timedDestruction(verificationCodeRepository.save(code)); // 存在就再次发送原来的验证码 } else { content = ElAdminConstant.EMAIL_CODE + verificationCode.getCode() + "</p>"; emailVo = new EmailVo(Arrays.asList(verificationCode.getValue()),"eladmin后台管理系统",content); } return emailVo; } @Override public void validated(VerificationCode code) { VerificationCode verificationCode = verificationCodeRepository.findByScenesAndTypeAndValueAndStatusIsTrue(code.getScenes(),code.getType(),code.getValue()); if(verificationCode == null || !verificationCode.getCode().equals(code.getCode())){ throw new BadRequestException("无效验证码"); } else { verificationCode.setStatus(false); verificationCodeRepository.save(verificationCode); } } /** * 定时任务,指定分钟后改变验证码状态 * @param verifyCode */ private void timedDestruction(VerificationCode verifyCode) { //以下示例为程序调用结束继续运行 ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor(); try { executorService.schedule(() -> { verifyCode.setStatus(false); verificationCodeRepository.save(verifyCode); }, expiration * 60 * 1000L, TimeUnit.MILLISECONDS); }catch (Exception e){ e.printStackTrace(); } } }
package me.zhengjie.system.repository; import me.zhengjie.system.domain.VerificationCode; import org.springframework.data.jpa.repository.JpaRepository; /** * @author jie * @date 2018-12-26 */ public interface VerificationCodeRepository extends JpaRepository<VerificationCode, Long> { /** * 获取有效的验证码 * @param scenes 业务场景,如重置密码,重置邮箱等等 * @param type * @param value * @return */ VerificationCode findByScenesAndTypeAndValueAndStatusIsTrue(String scenes,String type,String value); }