java web 郵件發送全過程(鏈接中攜帶的用戶信息經過加密處理)

本次以密碼找回使用郵箱方式找回爲例

步驟:可能相互調用有點亂,但是我寫的很清楚,應該不難看懂

1、獲取用戶名和郵箱,寫好郵件內容,發送郵件:

2、上一步調用的郵件發送方法,在這裏實現

3、數據加密,第一步中用到了加密。第四步用到了解密(這裏都是被調用的方法):

4、由於發送的鏈接定位到是重置頁面,也就是他給你隨機分配一個新密碼,你可以拿着這個新密碼重新登陸,然後去修改,這裏主要是講如何將獲得加密數據解密,並返回隨機密碼

郵件發送需要兩個jar包要引進,保存在百度雲資源裏,連接如下:

jar包 提取碼:cbsu

1、獲取用戶名和郵箱,寫好郵件內容,發送郵件:

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("utf-8");
        response.setContentType("application/json;charset=utf-8");
        String name=request.getParameter("username");
        String email=request.getParameter("email");
        Map<String, Object> res = new HashMap<>();
        String error=null;
        if ("".equals(email)) {
            error="郵箱不能爲空";
        }
       else {
            //我的用戶類User
            User user= null;
            try {
                //在我的用戶數據庫表中通過名字查找用戶是否存在
                user = UserDao.getByName(name);
                System.out.println(user);
                if (user == null) {
                    error="該用戶不存在";
                }else
                {
                    //如果用戶存在,還要查看對應用戶的email是否一致
                    String emails=user.getEmail();
                    if(!emails.equals(email)){
                         error="郵箱不正確";
                    }else{
                        //正式編寫郵件內容
                        //計算token
                        String token=String.format("%s,%s,%s,%s",user.getUid(),user.getUsername(),user.getEmail(),System.currentTimeMillis());
                        //加密,這裏調用下面的SecureUtils類中的加密算法
                        token = SecureUtils._3DES_encode(emailKEY, token.getBytes());
                        //計算url,先獲取你找回密碼的URL地址,再加上你的加密token(爲了防止有人冒充你的身份信息)
                        String url=request.getRequestURL().toString();
                        url=url.replace(request.getRequestURI(),"");
                        url=url+request.getContextPath()+"/Reset?token="+token;
                        //發送郵件,這裏的 MailUtils.sendMail在下面
                        System.out.println(email+" "+token);
                        //第二個參數爲context,自定義郵件內容,
                        MailUtils.sendMail(user.getEmail(),"重置鏈接:"+url);
                    }
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }

        }
        //將錯誤信息返回給去前端,沒有錯誤的話返回null
        res.put("mess",error);
        System.out.println("返回信息"+error);
        response.getWriter().write(new Gson().toJson(res));
    }
}

2、上一步調用的郵件發送方法,在這裏實現

package utils;


import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import java.util.Date;
import java.util.Properties;

public class MailUtils {
    public static final String HOST ="smtp.xxxx.com";//郵件服務器,這裏怎麼寫自行百度,根據你發郵件的郵件服務器不同
    public static final String USERNAME ="[email protected]";//賬戶用戶名
    public static final String PASSWORD ="Qhj12345";//密碼

    public static boolean sendMail(String to, String content) {
           //設置屬性
        Properties props = new Properties();
        props.put("mail.smtp.HOST", HOST);
        props.put("mail.smtp.auth", "true");
        props.put("mail.smtp.port", "25");
        // 環境信息
        Session session = Session.getDefaultInstance(props,
                new Authenticator() {
                    @Override
                    public PasswordAuthentication getPasswordAuthentication() {
                        // 在session中設置賬戶信息,Transport發送郵件時會使用
                        return new PasswordAuthentication(USERNAME, PASSWORD);
                    }
                });

        try {
            //郵件
            MimeMessage msg = new MimeMessage(session);
            //發件人
            msg.setFrom(new InternetAddress(USERNAME));
            //設置收件人
            msg.setRecipients(Message.RecipientType.BCC, InternetAddress.parse(to));
            msg.setSubject("重置密碼");
            //整封郵件的MIME消息體
            Multipart mp = new MimeMultipart();
            MimeBodyPart mbpContent = new MimeBodyPart();//附件
            mbpContent.setContent(content, "text/html;charset=utf-8");
            mp.addBodyPart(mbpContent);
            msg.setContent(mp);
            msg.setSentDate(new Date());
            msg.saveChanges();

            //發送郵件
            Transport transport = session.getTransport("smtp");
            transport.connect(HOST, USERNAME, PASSWORD);
            transport.sendMessage(msg, msg.getAllRecipients());
            transport.close();
        } catch (Exception mex) {
            mex.printStackTrace();
            return false;
        }
        return true;
    }

}

3、數據加密,第一步中用到了加密。第四步用到了解密(這裏都是被調用的方法):

package utils;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Random;
import java.util.UUID;

public class SecureUtils {

    private static final String Iv = "\0\0\0\0\0\0\0\0";

    private static final String Transformation = "DESede/CBC/PKCS5Padding";

    public static String fixedHexString(byte[] hashBytes) {
        StringBuffer sb = new StringBuffer();

        for (int i = 0; i < hashBytes.length; ++i) {
            sb.append(Integer.toString((hashBytes[i] & 255) + 256, 16).substring(1));
        }

        return sb.toString();
    }
    //des加密
    public static String _3DES_encode(byte[] key, byte[] data) {
        SecretKey deskey = new SecretKeySpec(key, "DESede");
        IvParameterSpec iv = new IvParameterSpec(Iv.getBytes());
        try {
            Cipher c1 = Cipher.getInstance(Transformation);
            c1.init(Cipher.ENCRYPT_MODE, deskey, iv);
            byte[] re = c1.doFinal(data);
            return fixedHexString(re);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
//解密
    public static String _3DES_decode(byte[] key, byte[] data) {
        SecretKey deskey = new SecretKeySpec(key, "DESede");
        IvParameterSpec iv = new IvParameterSpec(Iv.getBytes());
        try {
            Cipher c1 = Cipher.getInstance(Transformation);
            c1.init(Cipher.DECRYPT_MODE, deskey, iv);
            byte[] re = c1.doFinal(data);
            return new String(re);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static byte[] hexstr2bytearray(String str) {
        byte[] re = new byte[str.length() / 2];
        for (int i = 0; i < re.length; i++) {
            int r = Integer.parseInt(str.substring(i * 2, i * 2 + 2), 16);
            re[i] = (byte) r;
        }
        return re;
    }

    public static String getMD5(String str) throws NoSuchAlgorithmException {
        MessageDigest md = MessageDigest.getInstance("MD5");
        md.update(str.getBytes());
        return new BigInteger(1, md.digest()).toString(16);
    }

    //生成隨機數字和字母,
    public static String getStringRandom(int length) {

        String val = "";
        Random random = new Random();

        //參數length,表示生成幾位隨機數
        for (int i = 0; i < length; i++) {

            String charOrNum = random.nextInt(2) % 2 == 0 ? "char" : "num";
            //輸出字母還是數字
            if ("char".equalsIgnoreCase(charOrNum)) {
                //輸出是大寫字母還是小寫字母
                int temp = random.nextInt(2) % 2 == 0 ? 65 : 97;
                val += (char) (random.nextInt(26) + temp);
            } else if ("num".equalsIgnoreCase(charOrNum)) {
                val += String.valueOf(random.nextInt(10));
            }
        }
        return val;
    }

    public static String getUUID() {
        UUID uuid = UUID.randomUUID();
        String str = uuid.toString();
        String uuidStr = str.replace("-", "");
        return uuidStr;
    }
}

4、由於發送的鏈接定位到是重置頁面,也就是他給你隨機分配一個新密碼,你可以拿着這個新密碼重新登陸,然後去修改,這裏主要是講如何將獲得加密數據解密,並返回隨機密碼

package servlet;

import dao.UserDao;
import entity.User;
import utils.SecureUtils;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

@WebServlet(name = "Reset",urlPatterns = "/Reset")
public class Reset extends HttpServlet{
    private byte[] emailKEY = "yfHyN!5nyvtfMs9nF1P2QRkx".getBytes();
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req,resp);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html;charset=utf-8");
        String token=request.getParameter("token");
        PrintWriter out=response.getWriter();
        if("".equals(token)){
            out.println("請不要直接訪問這個鏈接!!!");
        }
        if (token.length() < 10) {
            out.println("非法token");
        }
        try {
            //解密
            token = SecureUtils._3DES_decode(emailKEY, SecureUtils.hexstr2bytearray(token));
            if (token == null) {
                out.println("非法token");
            }
            //這裏的值的個數,是根據你第一步創建token是攜帶了一個信息決定的,我帶了四個
            String[] tmp = token.split(",", 4);
            if (tmp.length != 4 || tmp[0].length() == 0 || tmp[1].length() == 0 || tmp[2].length() == 0||tmp[3].length()==0) {
                out.println("非法token");
            }
            long time = Long.parseLong(tmp[3]);
            if (System.currentTimeMillis() - time > 10*60*1000) {
                out.println("該重置鏈接已經超時");
            }
            String uname=tmp[1];
            User user= UserDao.getByName(uname);
            if(user==null) {
                out.println("用戶不存在");
            }
            if(tmp[1].equals(user.getUsername())&&tmp[2].equals(user.getEmail())){
                String password=SecureUtils.getStringRandom(6);
                UserDao.updatePassword(uname,password);
               out.println("你的新密碼是:"+password);
            }else{
                out.println("驗證失敗!!請重新驗證!!");
            }
        } catch (Throwable e) {
            out.println("非法token");
        }
    }
}

這裏只是舉例借鑑,實際應用到自己項目還是要修改的,給出參考思路,對於第二、三步可以直接使用粘貼,因爲這是我直接拿自己項目寫的,所以1,4步稍有不同

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章