邮箱验证流程与token生成

邮箱验证流程与token生成,第1张

该过程仅供参考,若有优化与建议,欢迎提出。

目录
  • 依赖
  • 邮箱验证
    • 邮箱工具类
    • 检查邮箱格式
    • Cache缓存
    • SendEmail方法
  • token 生成

依赖
		
      	<dependency>
      		<groupId>javax.mailgroupId>
      		<artifactId>mailartifactId>
      		<version>1.4.7version>
    	dependency>
		
      	<dependency>
    		<groupId>com.google.guavagroupId>
    		<artifactId>guavaartifactId>
    		<version>28.2-jreversion>
    	dependency>
邮箱验证 邮箱工具类

此处用的是线程的方式,Callable更容易设置是否超时

import java.util.Date;
import java.util.Properties;
import java.util.concurrent.Callable;


import javax.mail.Message;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

public class SEmail implements Callable<Boolean>{
	private static String USERNAME = "";//邮箱地址XXX@XX.XX
	/*
	* POP3/IMAP/SMTP/Exchange/CardDAV/CalDAV服务
	*需要给你的邮箱开启该功能,并填写相应信息
	*/
	private static String PASSWORD = "";//填写你的邮箱的授权码
	private static String HOST = "";//选择一个可用的服务器
	private String email;//目标邮箱
	private String code;//生成的验证码
	
	
	public SEmail(String email,String code){
		this.email = email;
		this.code = code;
	}
	public Boolean call() throws Exception{
		Transport transport = null;
		Properties prop = new Properties();
		prop.setProperty("mail.smtp.host", HOST);
		prop.setProperty("mai.transport.protocol", "smtp");
		prop.setProperty("mail.smtp.auth","true");
		Session session = Session.getDefaultInstance(prop);
		MimeMessage message = new MimeMessage(session);
		message.setFrom(new InternetAddress(USERNAME));
		message.setRecipient(Message.RecipientType.TO,new InternetAddress(email));
		message.setSentDate(new Date());
		message.setSubject("邮件验证码");
		String info = "\r\n" + 
				" + 
				"\r\n" + 
				"	\r\n" + 
				"	验证码\r\n" + 
				"\r\n" + 
				"	\r\n" + 
				"	欢迎您使用XXX,这是您的验证码,请于X分钟内输入激活码\r\n" + 
				"	

"+ code +"

"
+ " \r\n" + ""; message.setContent(info,"text/html;charset=UTF-8"); message.saveChanges(); session.setDebug(false); transport = session.getTransport("smtp"); transport.connect(USERNAME,PASSWORD); transport.sendMessage(message, message.getAllRecipients()); return true; } }
检查邮箱格式
public class CheckData {
    private static String NUM = ".*\d+.*";
    private static String SMALL = ".*[a-zA-Z]+.*";
    private static String CAPTIAL= ".*[a-zA-Z]+.*";
    private static String SYMBOL = ".*([~!@#$%^&*()_+|<>,.?/:;'\\[\\]{\\\\}\\\"]){1,}+.*";
    private static String EMAIL = "(\w+([-.][A-Za-z0-9]+)*){3,18}@\w+([-.][A-Za-z0-9]+)*\.\w+([-.][A-Za-z0-9]+)*";
    /*
	*邮箱格式检查
	*/
	public static boolean checkEmail(String email) {
		 if (email != null) {
	            return email.matches(EMAIL);
	        }
		 return false;
	}
	/*
	*密码格式检查,此处是必须要有带小写+数字+不能有特殊符号
	*/
	public static boolean checkPass(String password) {
		if (password == null){
			return false;
		}
		int size = password.length();
		if(size < 6||size >16) {
			return false;
		}
		if(password.matches(SYMBOL)) {
			return false;
		}
	    int n =  (password.matches(SMALL) ? 1 : 0) + (password.matches(NUM) ? 1 : 0) + (password.matches(CAPTIAL) ? 1 : 0);
	    return n==3;  
	}
}

Cache缓存

使用谷歌的一款包

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import java.util.concurrent.TimeUnit;

public class VerifyCodeCache {
	/**
     * 5分钟的验证码缓存,保障线程安全
     */
    private static volatile Cache<String,String> codeCache;

    private VerifyCodeCache(){}

    public static Cache<String,String> getCodeCache() {
       	//单例,懒汉模式
    	//双验证+同步锁
        if (codeCache == null) {
            synchronized (VerifyCodeCache.class) {
                if (codeCache == null) {
                    codeCache = CacheBuilder.newBuilder()
                            .expireAfterAccess(5, TimeUnit.MINUTES)
                            .maximumSize(100)
                            .concurrencyLevel(50).build();
                }
            }
        }
        return codeCache;
    }
}



SendEmail方法
	/*
	 * 此处使用固定大小的线程池,限制可同时发送的数目
	 * 允许10个线程同时执行
	 * */
	private ExecutorService executor = Executors.newFixedThreadPool(10); 
	/*
	 * 验证码缓存,单例
	 */
	private Cache<String,String> codeCache = VerifyCodeCache.getCodeCache();
	@ResponseBody
	@RequestMapping("")
	public String sendEmail(String email){
		...
		if(!CheckData.checkEmail(email)) {
			resMessage.setAll(StatusCode.send_fail,"邮箱错误");
			...
		}
		StringBuilder builder = new StringBuilder();
		Random random = new Random();
		for(int i = 0 ; i<8;i++) {
			builder.append(random.nextInt(9));
		}
		Future<Boolean> future = executor.submit(new SEmail(email,builder.toString()));
		try {
			//等待30秒,未执行完成,抛出中断异常
			future.get(30, TimeUnit.SECONDS);
			//放入对应邮箱以及验证码
			codeCache.put(email, builder.toString());
			...
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.getStackTrace();
		} catch (ExecutionException e) {
			// TODO Auto-generated catch block
			e.getStackTrace();
		} catch (TimeoutException e) {
			// TODO Auto-generated catch block
			e.getStackTrace();
		}
		...
	}
token 生成

此处用的是Java自带的加密模式,以及自己的加密密钥
注意,UTF-8的byte与String 相互转换会不一样,因为无法表示,因此,使用的是ISO-8859-1

/*
*密钥
*/
 private final static Key SECRET_KEY = new SecretKeySpec("密钥内容".getBytes(),"AES");
	/*
	 * 生成key
	 * */
	public static String createToken(String uuid) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException {
		//获取当前时间
		long currentTimeMillis = System.currentTimeMillis();
		/*token中即为加密信息,可以自己随意设置
		 *此处为了方便,用的是uuid+有效时间
		 *TIME_OUT:为有时长,后通过比较,即可判断是否过期
		 */
		String token = uuid + ":"+(currentTimeMillis + TIME_OUT);
	    Cipher cipher = Cipher.getInstance("AES");
	    cipher.init(Cipher.ENCRYPT_MODE, SECRET_KEY);
	    return new String(cipher.doFinal(token.getBytes()),"ISO-8859-1");
	}
	/*
	 * 还原
	 * */
    public static String transferToken(String token) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException{
    	Cipher cipher = Cipher.getInstance("AES");
	    cipher.init(Cipher.DECRYPT_MODE, SECRET_KEY);
	    byte[] newData = cipher.doFinal(token.getBytes("ISO-8859-1"));
	    String res = new String(newData);
		return res;
    }

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/877008.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-13
下一篇 2022-05-13

发表评论

登录后才能评论

评论列表(0条)

保存