JavaMail學習筆記(七)帳號激活與忘記密碼 實例

 

一、帳戶激活


          在很多時候,在某些網站註冊一個用戶之後,網站會給這個用戶註冊時填寫的email地址發送一封帳戶激活郵件,這封郵件的內容就是一個激活帳戶鏈接和一段簡短的文字描述,如果用戶沒有去郵箱將帳戶激活,可能在使用網站的某些功能時就會受到限制,比如不能發貼、下載資料、評論等限制。這麼做的原因應該是爲了保證帳戶的安全性和郵箱的有效性,以後網站如果有什麼活動、資訊或系統安全通知等,可以在第一時間通知到用戶。比如我在奇藝視頻網站註冊一個帳號之後,它就會往我註冊時填寫的郵箱中發一封帳戶激活的郵件,郵件中有一個激活的鏈接,點擊它就可以將你的帳戶激活。如下圖所示:


這個功能是怎麼做到的呢,其實實現也是很簡單的,說白了就是一個Update操作。

實現思路:當一個用戶註冊成功之後,系統向用戶註冊時提供的email地址發送一封郵件,郵件的內容是一個激活帳戶的鏈接和一段簡短的文字描述,這個鏈接的功能就是將這個帳戶的狀態修改成激活狀態。這個功能的重點在於如何生成這個激活帳戶的鏈接。直接可以聯想到的方法就是建一個Servlet,Servlet接收一個用戶名參數,Servlet拿到用戶名參數之後,到數據庫把這條記錄load出來,做一次update操作即可。但是這樣做會有風險,比如有人想在你的網站上搞破壞,註冊時他填的email地址就是亂填的,這個Email地址可能根本就收不到郵件(但符合email格式),註冊完成之後,然後在瀏覽器地址欄輸入網站之前發送的帳戶激活鏈接,並加上新註冊的用戶名參數,這樣一來就跳過了去郵箱激活的步聚,時間久了,庫中可能會留下許多無效的email地址和帳戶。爲了避免這個問題,解決方案是在用戶註冊成功之後,在發送激活帳戶的鏈接中加一個隨機碼,這個隨機碼是將用戶名和一個隨機數用md5加密後的一串16進制字符串,每次用戶在激活帳戶的時候,都驗證這個隨機碼是否和註冊時發送的一致,這樣就可以避免人爲的修改激活鏈接達到帳戶激活的功能。


二、忘記密碼


          當你在某網站註冊一個帳戶之後,發現這個帳戶很久沒用了,密碼也忘記了,如果還記得之前註冊時填寫的Email,那就可以向你的email中發一個重設密碼的鏈接,就可以重新設置你的密碼。大部份網站一般都提供了根據Email找回密碼的功能。實現此功能的思路:在登錄界面添加一個“忘記密碼的鏈接,用戶點擊進去之後,輸入用戶名或Email,系統根據用戶名或Email找出用戶信息,並生成一個重新設置密碼的鏈接發送到用戶的郵箱中(生成鏈接的方式和生成帳戶激活鏈接的方式一樣),用戶在郵箱中點擊重設密碼的鏈接,根據提示進入密碼重設頁面,重新輸入新的密碼即可。

功能實現步聚(帳號激活):

1、用戶註冊頁面

  1. <form action="${pageContext.request.contextPath}/register" method="post"> 
  2.     用戶名:<input type="text" name="userName" value="${param.userName}"><span class="error">${errors.userName}</span><br/> 
  3.     密碼:<input type="password" name="password" ><span class="error">${errors.password}</span><br/> 
  4.     確認密碼:<input type="password" name="password2"><span class="error">${errors.password2}</span><br/> 
  5.     email:<input type="text" name="email" value="${param.email}"><span class="error">${errors.email}</span><br/> 
  6.     <input type="submit" value="註冊"> 
  7. </form> 
<form action="${pageContext.request.contextPath}/register" method="post">
	用戶名:<input type="text" name="userName" value="${param.userName}"><span class="error">${errors.userName}</span><br/>
	密碼:<input type="password" name="password" ><span class="error">${errors.password}</span><br/>
	確認密碼:<input type="password" name="password2"><span class="error">${errors.password2}</span><br/>
	email:<input type="text" name="email" value="${param.email}"><span class="error">${errors.email}</span><br/>
	<input type="submit" value="註冊">
</form>

2、處理註冊請求的Servlet(RegisterServlet)

  1. package org.study.accountactivate.web.servlet; 
  2.  
  3. import java.io.IOException; 
  4. import java.util.HashMap; 
  5. import java.util.Map; 
  6.  
  7. import javax.servlet.ServletException; 
  8. import javax.servlet.http.HttpServlet; 
  9. import javax.servlet.http.HttpServletRequest; 
  10. import javax.servlet.http.HttpServletResponse; 
  11.  
  12. import org.study.accountactivate.dao.UserDao; 
  13. import org.study.accountactivate.dao.impl.UserDaoImpl; 
  14. import org.study.accountactivate.domail.User; 
  15. import org.study.accountactivate.util.EmailUtils; 
  16.  
  17. /**
  18. * 用戶註冊
  19. */ 
  20. public class RegisterServlet extends HttpServlet { 
  21.     private static final long serialVersionUID = 1L; 
  22.      
  23.     private UserDao userDao = UserDaoImpl.getInstance(); 
  24.         
  25.     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 
  26.         doPost(request, response); 
  27.     } 
  28.  
  29.     protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 
  30.         String userName = request.getParameter("userName"); 
  31.         String password = request.getParameter("password"); 
  32.         String password2 = request.getParameter("password2"); 
  33.         String email = request.getParameter("email"); 
  34.          
  35.         Map<String, String> errors = new HashMap<String,String>(); 
  36.         if (userName == null || "".equals(userName)) { 
  37.             errors.put("userName", "用戶名不能爲空!"); 
  38.         } else if (userName != null && userDao.findUserByName(userName) != null) { 
  39.             errors.put("userName", "該用戶已註冊!"); 
  40.         } 
  41.          
  42.         if (password == null || "".equals(password)) { 
  43.             errors.put("password","密碼不能爲空!"); 
  44.         } else if (password != null && password.length() < 3) { 
  45.             errors.put("password","密碼長度不能低於3位!"); 
  46.         } 
  47.          
  48.         if (password2 == null || "".equals(password2)) { 
  49.             errors.put("password2", "確認密碼不能爲空!"); 
  50.         } else if (password2 != null && !password2.equals(password)) { 
  51.             errors.put("password2", "兩次輸入的密碼不一致!"); 
  52.         } 
  53.          
  54.         if (email == null || "".equals(email)) { 
  55.             errors.put("email", "email不能爲空!"); 
  56.              
  57.         } else if (email != null && !email.matches("[0-9a-zA-Z_-]+@[0-9a-zA-Z_-]+\\.[0-9a-zA-Z_-]+(\\.[0-9a-zA-Z_-])*")) { 
  58.             errors.put("email", "email格式不正確!"); 
  59.         } 
  60.          
  61.         if (!errors.isEmpty()) { 
  62.             request.setAttribute("errors", errors); 
  63.             request.getRequestDispatcher("/registerUI").forward(request, response); 
  64.             return
  65.         } 
  66.          
  67.         User user = new User(); 
  68.         user.setUserName(userName); 
  69.         user.setPassword(password); 
  70.         user.setEmail(email); 
  71.         user.setActivated(false); 
  72.          
  73.         userDao.addUser(user); 
  74.          
  75.         // 註冊成功後,發送帳戶激活鏈接 
  76.         EmailUtils.sendAccountActivateEmail(user); 
  77.          
  78.         // 註冊成功直接將當前用戶保存到session中 
  79.         request.getSession().setAttribute("user", user); 
  80.         request.getRequestDispatcher("/WEB-INF/pages/registerSuccess.jsp").forward(request,response); 
  81.     } 
package org.study.accountactivate.web.servlet;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.study.accountactivate.dao.UserDao;
import org.study.accountactivate.dao.impl.UserDaoImpl;
import org.study.accountactivate.domail.User;
import org.study.accountactivate.util.EmailUtils;

/**
 * 用戶註冊
 */
public class RegisterServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
	
	private UserDao userDao = UserDaoImpl.getInstance();
       
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doPost(request, response);
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		String userName = request.getParameter("userName");
		String password = request.getParameter("password");
		String password2 = request.getParameter("password2");
		String email = request.getParameter("email");
		
		Map<String, String> errors = new HashMap<String,String>();
		if (userName == null || "".equals(userName)) {
			errors.put("userName", "用戶名不能爲空!");
		} else if (userName != null && userDao.findUserByName(userName) != null) {
			errors.put("userName", "該用戶已註冊!");
		}
		
		if (password == null || "".equals(password)) {
			errors.put("password","密碼不能爲空!");
		} else if (password != null && password.length() < 3) {
			errors.put("password","密碼長度不能低於3位!");
		}
		
		if (password2 == null || "".equals(password2)) {
			errors.put("password2", "確認密碼不能爲空!");
		} else if (password2 != null && !password2.equals(password)) {
			errors.put("password2", "兩次輸入的密碼不一致!");
		}
		
		if (email == null || "".equals(email)) {
			errors.put("email", "email不能爲空!");
			
		} else if (email != null && !email.matches("[0-9a-zA-Z_-]+@[0-9a-zA-Z_-]+\\.[0-9a-zA-Z_-]+(\\.[0-9a-zA-Z_-])*")) {
			errors.put("email", "email格式不正確!");
		}
		
		if (!errors.isEmpty()) {
			request.setAttribute("errors", errors);
			request.getRequestDispatcher("/registerUI").forward(request, response);
			return;
		}
		
		User user = new User();
		user.setUserName(userName);
		user.setPassword(password);
		user.setEmail(email);
		user.setActivated(false);
		
		userDao.addUser(user);
		
		// 註冊成功後,發送帳戶激活鏈接
		EmailUtils.sendAccountActivateEmail(user);
		
		// 註冊成功直接將當前用戶保存到session中
		request.getSession().setAttribute("user", user);
		request.getRequestDispatcher("/WEB-INF/pages/registerSuccess.jsp").forward(request,response);
	}
}

3、激活帳戶的Servlet(ActivateAccountServle)

  1. package org.study.accountactivate.web.servlet; 
  2.  
  3. import java.io.IOException; 
  4. import javax.servlet.ServletException; 
  5. import javax.servlet.http.HttpServlet; 
  6. import javax.servlet.http.HttpServletRequest; 
  7. import javax.servlet.http.HttpServletResponse; 
  8.  
  9. import org.study.accountactivate.dao.UserDao; 
  10. import org.study.accountactivate.dao.impl.UserDaoImpl; 
  11. import org.study.accountactivate.domail.User; 
  12. import org.study.accountactivate.util.GenerateLinkUtils; 
  13.  
  14. /**
  15. * 帳戶激活
  16. */ 
  17. public class ActivateAccountServlet extends HttpServlet { 
  18.     private static final long serialVersionUID = 1L; 
  19.         
  20.     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 
  21.         String idValue = request.getParameter("id"); 
  22.         int id = -1
  23.         try
  24.             id = Integer.parseInt(idValue); 
  25.         } catch (NumberFormatException e) { 
  26.             throw new RuntimeException("無效的用戶!"); 
  27.         } 
  28.         UserDao userDao = UserDaoImpl.getInstance(); 
  29.         User user = userDao.findUserById(id);// 得到要激活的帳戶 
  30.         user.setActivated(GenerateLinkUtils.verifyCheckcode(user, request));// 校驗驗證碼是否和註冊時發送的一致,以此設置是否激活該帳戶 
  31.         userDao.updateUser(user); 
  32.          
  33.         request.getSession().setAttribute("user", user); 
  34.          
  35.         request.getRequestDispatcher("/accountActivateUI").forward(request, response); 
  36.     } 
  37.  
  38.     protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 
  39.         doGet(request, response); 
  40.     } 
package org.study.accountactivate.web.servlet;

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

import org.study.accountactivate.dao.UserDao;
import org.study.accountactivate.dao.impl.UserDaoImpl;
import org.study.accountactivate.domail.User;
import org.study.accountactivate.util.GenerateLinkUtils;

/**
 * 帳戶激活
 */
public class ActivateAccountServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
       
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		String idValue = request.getParameter("id");
		int id = -1;
		try {
			id = Integer.parseInt(idValue);
		} catch (NumberFormatException e) {
			throw new RuntimeException("無效的用戶!");
		}
		UserDao userDao = UserDaoImpl.getInstance();
		User user = userDao.findUserById(id);// 得到要激活的帳戶
		user.setActivated(GenerateLinkUtils.verifyCheckcode(user, request));// 校驗驗證碼是否和註冊時發送的一致,以此設置是否激活該帳戶
		userDao.updateUser(user);
		
		request.getSession().setAttribute("user", user);
		
		request.getRequestDispatcher("/accountActivateUI").forward(request, response);
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doGet(request, response);
	}
}

4、操作用戶的DAO接口與實現類(UserDao和UserDaoImpl類)

  1. package org.study.accountactivate.dao; 
  2.  
  3. import org.study.accountactivate.domail.User; 
  4.  
  5. public interface UserDao { 
  6.  
  7.     void addUser(User user); 
  8.      
  9.     void updateUser(User user); 
  10.      
  11.     User findUserById(int id); 
  12.      
  13.     User findUserByName(String userName); 
  14.      
  15.     User findUserByNameOrEmail(String nameOrEmail); 
  16.  
  17. package org.study.accountactivate.dao.impl; 
  18.  
  19. import java.util.Collection; 
  20. import java.util.HashMap; 
  21. import java.util.Iterator; 
  22. import java.util.Map; 
  23. import java.util.UUID; 
  24.  
  25. import org.study.accountactivate.dao.UserDao; 
  26. import org.study.accountactivate.domail.User; 
  27.  
  28. public class UserDaoImpl implements UserDao { 
  29.      
  30.     private static UserDaoImpl instance = new UserDaoImpl(); 
  31.      
  32.     private UserDaoImpl() {} 
  33.      
  34.     public static UserDaoImpl getInstance() { 
  35.         return instance; 
  36.     } 
  37.      
  38.     Map<Integer,User> users = new HashMap<Integer, User>(); 
  39.      
  40.     int nextId = 1
  41.  
  42.     @Override 
  43.     public void addUser(User user) { 
  44.         user.setId(nextId++); 
  45.         user.setRandomCode(UUID.randomUUID().toString()); 
  46.         users.put(user.getId(), user); 
  47.     } 
  48.  
  49.     @Override 
  50.     public void updateUser(User user) { 
  51.         users.put(user.getId(), user); 
  52.     } 
  53.  
  54.     @Override 
  55.     public User findUserById(int id) { 
  56.         return users.get(id); 
  57.     } 
  58.  
  59.     @Override 
  60.     public User findUserByName(String userName) { 
  61.         Collection<User> userValues = users.values(); 
  62.         for (Iterator<User> iterator = userValues.iterator();iterator.hasNext();) { 
  63.             User user = iterator.next(); 
  64.             if (user.getUserName().equals(userName)) { 
  65.                 return user; 
  66.             } 
  67.         } 
  68.         return null
  69.     } 
  70.  
  71.     @Override 
  72.     public User findUserByNameOrEmail(String nameOrEmail) { 
  73.         Collection<User> userValues = users.values(); 
  74.         for(Iterator<User> iterator = userValues.iterator();iterator.hasNext();) { 
  75.             User user = iterator.next(); 
  76.             if (user.getEmail().equals(nameOrEmail) || user.getUserName().equals(nameOrEmail)) { 
  77.                 return user; 
  78.             } 
  79.         } 
  80.         return null
  81.     } 
package org.study.accountactivate.dao;

import org.study.accountactivate.domail.User;

public interface UserDao {

	void addUser(User user);
	
	void updateUser(User user);
	
	User findUserById(int id);
	
	User findUserByName(String userName);
	
	User findUserByNameOrEmail(String nameOrEmail);
}

package org.study.accountactivate.dao.impl;

import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.UUID;

import org.study.accountactivate.dao.UserDao;
import org.study.accountactivate.domail.User;

public class UserDaoImpl implements UserDao {
	
	private static UserDaoImpl instance = new UserDaoImpl();
	
	private UserDaoImpl() {}
	
	public static UserDaoImpl getInstance() {
		return instance;
	}
	
	Map<Integer,User> users = new HashMap<Integer, User>();
	
	int nextId = 1;

	@Override
	public void addUser(User user) {
		user.setId(nextId++);
		user.setRandomCode(UUID.randomUUID().toString());
		users.put(user.getId(), user);
	}

	@Override
	public void updateUser(User user) {
		users.put(user.getId(), user);
	}

	@Override
	public User findUserById(int id) {
		return users.get(id);
	}

	@Override
	public User findUserByName(String userName) {
		Collection<User> userValues = users.values();
		for (Iterator<User> iterator = userValues.iterator();iterator.hasNext();) {
			User user = iterator.next();
			if (user.getUserName().equals(userName)) {
				return user;
			}
		}
		return null;
	}

	@Override
	public User findUserByNameOrEmail(String nameOrEmail) {
		Collection<User> userValues = users.values();
		for(Iterator<User> iterator = userValues.iterator();iterator.hasNext();) {
			User user = iterator.next();
			if (user.getEmail().equals(nameOrEmail) || user.getUserName().equals(nameOrEmail)) {
				return user;
			}
		}
		return null;
	}
}

5、發送Email的工具類(EmailUtils,用於發送帳戶激活鏈接和密碼重置鏈接)

  1. package org.study.accountactivate.util; 
  2.  
  3. import java.io.IOException; 
  4. import java.io.InputStream; 
  5. import java.util.Date; 
  6. import java.util.Properties; 
  7.  
  8. import javax.mail.Authenticator; 
  9. import javax.mail.Message.RecipientType; 
  10. import javax.mail.PasswordAuthentication; 
  11. import javax.mail.Session; 
  12. import javax.mail.Transport; 
  13. import javax.mail.internet.InternetAddress; 
  14. import javax.mail.internet.MimeMessage; 
  15.  
  16. import org.study.accountactivate.domail.User; 
  17.  
  18. public class EmailUtils { 
  19.      
  20.     private static final String FROM = "[email protected]"
  21.  
  22.     /**
  23.      * 註冊成功後,向用戶發送帳戶激活鏈接的郵件
  24.      * @param user 未激活的用戶
  25.      */ 
  26.     public static void sendAccountActivateEmail(User user) { 
  27.         Session session = getSession(); 
  28.         MimeMessage message = new MimeMessage(session); 
  29.         try
  30.             message.setSubject("帳戶激活郵件"); 
  31.             message.setSentDate(new Date()); 
  32.             message.setFrom(new InternetAddress(FROM)); 
  33.             message.setRecipient(RecipientType.TO, new InternetAddress(user.getEmail())); 
  34.             message.setContent("<a href='" + GenerateLinkUtils.generateActivateLink(user)+"'>點擊激活帳戶</a>","text/html;charset=utf-8"); 
  35.             // 發送郵件 
  36.             Transport.send(message); 
  37.         } catch (Exception e) { 
  38.             e.printStackTrace(); 
  39.         } 
  40.     } 
  41.      
  42.     /**
  43.      * 發送重設密碼鏈接的郵件
  44.      */ 
  45.     public static void sendResetPasswordEmail(User user) { 
  46.         Session session = getSession(); 
  47.         MimeMessage message = new MimeMessage(session); 
  48.         try
  49.             message.setSubject("找回您的帳戶與密碼"); 
  50.             message.setSentDate(new Date()); 
  51.             message.setFrom(new InternetAddress(FROM)); 
  52.             message.setRecipient(RecipientType.TO, new InternetAddress(user.getEmail())); 
  53.             message.setContent("要使用新的密碼, 請使用以下鏈接啓用密碼:<br/><a href='" + GenerateLinkUtils.generateResetPwdLink(user) +"'>點擊重新設置密碼</a>","text/html;charset=utf-8"); 
  54.             // 發送郵件 
  55.             Transport.send(message); 
  56.         } catch (Exception e) { 
  57.             e.printStackTrace(); 
  58.         } 
  59.     } 
  60.      
  61.     public static Session getSession() { 
  62.         Properties props = new Properties(); 
  63.         props.setProperty("mail.transport.protocol", "smtp"); 
  64.         props.setProperty("mail.smtp.host", "smtp.163.com"); 
  65.         props.setProperty("mail.smtp.port", "25"); 
  66.         props.setProperty("mail.smtp.auth", "true"); 
  67.         Session session = Session.getInstance(props, new Authenticator() { 
  68.             @Override 
  69.             protected PasswordAuthentication getPasswordAuthentication() { 
  70.                 String password = null
  71.                 InputStream is = EmailUtils.class.getResourceAsStream("password.dat"); 
  72.                 byte[] b = new byte[1024]; 
  73.                 try
  74.                     int len = is.read(b); 
  75.                     password = new String(b,0,len); 
  76.                 } catch (IOException e) { 
  77.                     e.printStackTrace(); 
  78.                 } 
  79.                 return new PasswordAuthentication(FROM, password); 
  80.             } 
  81.              
  82.         }); 
  83.         return session; 
  84.     } 
package org.study.accountactivate.util;

import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.Properties;

import javax.mail.Authenticator;
import javax.mail.Message.RecipientType;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

import org.study.accountactivate.domail.User;

public class EmailUtils {
	
	private static final String FROM = "[email protected]";

	/**
	 * 註冊成功後,向用戶發送帳戶激活鏈接的郵件
	 * @param user 未激活的用戶
	 */
	public static void sendAccountActivateEmail(User user) {
		Session session = getSession();
		MimeMessage message = new MimeMessage(session);
		try {
			message.setSubject("帳戶激活郵件");
			message.setSentDate(new Date());
			message.setFrom(new InternetAddress(FROM));
			message.setRecipient(RecipientType.TO, new InternetAddress(user.getEmail()));
			message.setContent("<a href='" + GenerateLinkUtils.generateActivateLink(user)+"'>點擊激活帳戶</a>","text/html;charset=utf-8");
			// 發送郵件
			Transport.send(message);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 發送重設密碼鏈接的郵件
	 */
	public static void sendResetPasswordEmail(User user) {
		Session session = getSession();
		MimeMessage message = new MimeMessage(session);
		try {
			message.setSubject("找回您的帳戶與密碼");
			message.setSentDate(new Date());
			message.setFrom(new InternetAddress(FROM));
			message.setRecipient(RecipientType.TO, new InternetAddress(user.getEmail()));
			message.setContent("要使用新的密碼, 請使用以下鏈接啓用密碼:<br/><a href='" + GenerateLinkUtils.generateResetPwdLink(user) +"'>點擊重新設置密碼</a>","text/html;charset=utf-8");
			// 發送郵件
			Transport.send(message);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public static Session getSession() {
		Properties props = new Properties();
		props.setProperty("mail.transport.protocol", "smtp");
		props.setProperty("mail.smtp.host", "smtp.163.com");
		props.setProperty("mail.smtp.port", "25");
		props.setProperty("mail.smtp.auth", "true");
		Session session = Session.getInstance(props, new Authenticator() {
			@Override
			protected PasswordAuthentication getPasswordAuthentication() {
				String password = null;
				InputStream is = EmailUtils.class.getResourceAsStream("password.dat");
				byte[] b = new byte[1024];
				try {
					int len = is.read(b);
					password = new String(b,0,len);
				} catch (IOException e) {
					e.printStackTrace();
				}
				return new PasswordAuthentication(FROM, password);
			}
			
		});
		return session;
	}
}

6、生成帳戶激活、密碼重設鏈接的工具類(GenerateLinkUtils)

  1. package org.study.accountactivate.util; 
  2.  
  3. import java.security.MessageDigest; 
  4. import java.security.NoSuchAlgorithmException; 
  5.  
  6. import javax.servlet.ServletRequest; 
  7.  
  8. import org.study.accountactivate.domail.User; 
  9.  
  10. /**
  11. * 生成帳戶激活、重新設置密碼的鏈接
  12. */ 
  13. public class GenerateLinkUtils { 
  14.      
  15.     private static final String CHECK_CODE = "checkCode"
  16.      
  17.     /**
  18.      * 生成帳戶激活鏈接
  19.      */ 
  20.     public static String generateActivateLink(User user) { 
  21.         return "http://localhost:8080/AccountActivate/activateAccount?id="  
  22.                 + user.getId() + "&" + CHECK_CODE + "=" + generateCheckcode(user); 
  23.     } 
  24.      
  25.     /**
  26.      * 生成重設密碼的鏈接
  27.      */ 
  28.     public static String generateResetPwdLink(User user) { 
  29.         return "http://localhost:8080/AccountActivate/resetPasswordUI?userName="  
  30.                 + user.getUserName() + "&" + CHECK_CODE + "=" + generateCheckcode(user); 
  31.     } 
  32.      
  33.     /**
  34.      * 生成驗證帳戶的MD5校驗碼
  35.      * @param user  要激活的帳戶
  36.      * @return 將用戶名和密碼組合後,通過md5加密後的16進制格式的字符串
  37.      */ 
  38.     public static String generateCheckcode(User user) { 
  39.         String userName = user.getUserName(); 
  40.         String randomCode = user.getRandomCode(); 
  41.         return md5(userName + ":" + randomCode); 
  42.     } 
  43.      
  44.     /**
  45.      * 驗證校驗碼是否和註冊時發送的驗證碼一致
  46.      * @param user 要激活的帳戶
  47.      * @param checkcode 註冊時發送的校驗碼
  48.      * @return 如果一致返回true,否則返回false
  49.      */ 
  50.     public static boolean verifyCheckcode(User user,ServletRequest request) { 
  51.         String checkCode = request.getParameter(CHECK_CODE); 
  52.         return generateCheckcode(user).equals(checkCode); 
  53.     } 
  54.  
  55.     private static String md5(String string) { 
  56.         MessageDigest md = null
  57.         try
  58.             md = MessageDigest.getInstance("md5"); 
  59.             md.update(string.getBytes()); 
  60.             byte[] md5Bytes = md.digest(); 
  61.             return bytes2Hex(md5Bytes); 
  62.         } catch (NoSuchAlgorithmException e) { 
  63.             e.printStackTrace(); 
  64.         } 
  65.          
  66.         return null
  67.     } 
  68.      
  69.     private static String bytes2Hex(byte[] byteArray) 
  70.     { 
  71.         StringBuffer strBuf = new StringBuffer(); 
  72.         for (int i = 0; i < byteArray.length; i++) 
  73.         { 
  74.             if(byteArray[i] >= 0 && byteArray[i] < 16
  75.             { 
  76.                 strBuf.append("0"); 
  77.             } 
  78.             strBuf.append(Integer.toHexString(byteArray[i] & 0xFF)); 
  79.         } 
  80.         return strBuf.toString(); 
  81.     } 
package org.study.accountactivate.util;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

import javax.servlet.ServletRequest;

import org.study.accountactivate.domail.User;

/**
 * 生成帳戶激活、重新設置密碼的鏈接
 */
public class GenerateLinkUtils {
	
	private static final String CHECK_CODE = "checkCode";
	
	/**
	 * 生成帳戶激活鏈接
	 */
	public static String generateActivateLink(User user) {
		return "http://localhost:8080/AccountActivate/activateAccount?id=" 
				+ user.getId() + "&" + CHECK_CODE + "=" + generateCheckcode(user);
	}
	
	/**
	 * 生成重設密碼的鏈接
	 */
	public static String generateResetPwdLink(User user) {
		return "http://localhost:8080/AccountActivate/resetPasswordUI?userName=" 
				+ user.getUserName() + "&" + CHECK_CODE + "=" + generateCheckcode(user);
	}
	
	/**
	 * 生成驗證帳戶的MD5校驗碼
	 * @param user  要激活的帳戶
	 * @return 將用戶名和密碼組合後,通過md5加密後的16進制格式的字符串
	 */
	public static String generateCheckcode(User user) {
		String userName = user.getUserName();
		String randomCode = user.getRandomCode();
		return md5(userName + ":" + randomCode);
	}
	
	/**
	 * 驗證校驗碼是否和註冊時發送的驗證碼一致
	 * @param user 要激活的帳戶
	 * @param checkcode 註冊時發送的校驗碼
	 * @return 如果一致返回true,否則返回false
	 */
	public static boolean verifyCheckcode(User user,ServletRequest request) {
		String checkCode = request.getParameter(CHECK_CODE);
		return generateCheckcode(user).equals(checkCode);
	}

	private static String md5(String string) {
		MessageDigest md = null;
		try {
			md = MessageDigest.getInstance("md5");
			md.update(string.getBytes());
			byte[] md5Bytes = md.digest();
			return bytes2Hex(md5Bytes);
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		}
		
		return null;
	}
	
	private static String bytes2Hex(byte[] byteArray)
	{
		StringBuffer strBuf = new StringBuffer();
		for (int i = 0; i < byteArray.length; i++)
		{
			if(byteArray[i] >= 0 && byteArray[i] < 16)
			{
				strBuf.append("0");
			}
			strBuf.append(Integer.toHexString(byteArray[i] & 0xFF));
		}
		return strBuf.toString();
	}
}

7、實體類(User)

  1. package org.study.accountactivate.domail; 
  2.  
  3. public class User { 
  4.     // 編號 
  5.     private int id; 
  6.     // 用戶名 
  7.     private String userName; 
  8.     // 密碼 
  9.     private String password; 
  10.     // email 
  11.     private String email; 
  12.     // 是否激活 
  13.     private boolean activated; 
  14.     // 隨機碼(激活帳戶與生成重設密碼鏈接時使用) 
  15.     private String randomCode; 
  16.      
  17.     public int getId() { 
  18.         return id; 
  19.     } 
  20.     public void setId(int id) { 
  21.         this.id = id; 
  22.     } 
  23.     public String getUserName() { 
  24.         return userName; 
  25.     } 
  26.     public void setUserName(String userName) { 
  27.         this.userName = userName; 
  28.     } 
  29.     public String getPassword() { 
  30.         return password; 
  31.     } 
  32.     public void setPassword(String password) { 
  33.         this.password = password; 
  34.     } 
  35.     public boolean isActivated() { 
  36.         return activated; 
  37.     } 
  38.     public void setActivated(boolean activated) { 
  39.         this.activated = activated; 
  40.     } 
  41.     public String getRandomCode() { 
  42.         return randomCode; 
  43.     } 
  44.     public void setRandomCode(String randomCode) { 
  45.         this.randomCode = randomCode; 
  46.     } 
  47.     public String getEmail() { 
  48.         return email; 
  49.     } 
  50.     public void setEmail(String email) { 
  51.         this.email = email; 
  52.     } 
  53.  
package org.study.accountactivate.domail;

public class User {
	// 編號
	private int id;
	// 用戶名
	private String userName;
	// 密碼
	private String password;
	// email
	private String email;
	// 是否激活
	private boolean activated;
	// 隨機碼(激活帳戶與生成重設密碼鏈接時使用)
	private String randomCode;
	
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getUserName() {
		return userName;
	}
	public void setUserName(String userName) {
		this.userName = userName;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}
	public boolean isActivated() {
		return activated;
	}
	public void setActivated(boolean activated) {
		this.activated = activated;
	}
	public String getRandomCode() {
		return randomCode;
	}
	public void setRandomCode(String randomCode) {
		this.randomCode = randomCode;
	}
	public String getEmail() {
		return email;
	}
	public void setEmail(String email) {
		this.email = email;
	}

}

功能實現步驟(忘記密碼):

1、登錄頁面

  1. <form action="${pageContext.request.contextPath}/login" method="post"> 
  2.     <span class="error" style="display: block;">${errors.loginError}</span> 
  3.     用戶名:<input type="text" name="userName" value="${param.userName}"><span class="error">${errors.userName}</span><br/> 
  4.     密碼:<input type="password" name="password"><span class="error">${errors.password}</span><br/> 
  5.     <input type="submit" value="登錄">  
  6.     <a href="${pageContext.request.contextPath}/forgotPwdUI">忘記密碼?</a>  
  7.     <a href="${pageContext.request.contextPath}/registerUI">註冊</a> 
  8. </form> 
<form action="${pageContext.request.contextPath}/login" method="post">
	<span class="error" style="display: block;">${errors.loginError}</span>
	用戶名:<input type="text" name="userName" value="${param.userName}"><span class="error">${errors.userName}</span><br/>
	密碼:<input type="password" name="password"><span class="error">${errors.password}</span><br/>
	<input type="submit" value="登錄"> 
	<a href="${pageContext.request.contextPath}/forgotPwdUI">忘記密碼?</a> 
	<a href="${pageContext.request.contextPath}/registerUI">註冊</a>
</form>

2、發送重設密碼申請的頁面

  1. <form action="${pageContext.request.contextPath}/forgotPwd" method="post"> 
  2.     <span style="color: red">${requestScope.sendMailMsg}</span> 
  3.     用戶名/郵箱:<input type="text" name="userNameOrEmail" /><span style="color: red">${requestScope.errorMsg}</span><br/> 
  4.     <input type="submit" value="提交" /><a href=""></a> 
  5. </form> 
<form action="${pageContext.request.contextPath}/forgotPwd" method="post">
	<span style="color: red">${requestScope.sendMailMsg}</span>
	用戶名/郵箱:<input type="text" name="userNameOrEmail" /><span style="color: red">${requestScope.errorMsg}</span><br/>
	<input type="submit" value="提交" /><a href=""></a>
</form>

3、處理“發送重設密碼鏈接“請求的Servlet(ForgotPwdServlet)

  1. package org.study.accountactivate.web.servlet; 
  2.  
  3. import java.io.IOException; 
  4. import javax.servlet.ServletException; 
  5. import javax.servlet.http.HttpServlet; 
  6. import javax.servlet.http.HttpServletRequest; 
  7. import javax.servlet.http.HttpServletResponse; 
  8.  
  9. import org.study.accountactivate.dao.UserDao; 
  10. import org.study.accountactivate.dao.impl.UserDaoImpl; 
  11. import org.study.accountactivate.domail.User; 
  12. import org.study.accountactivate.util.EmailUtils; 
  13.  
  14. /**
  15. * 發送重設密碼申請的鏈接
  16. */ 
  17. public class ForgotPwdServlet extends HttpServlet { 
  18.      
  19.     private static final long serialVersionUID = 1L; 
  20.  
  21.     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 
  22.         String userNameOrEmail = request.getParameter("userNameOrEmail"); 
  23.         UserDao userDao = UserDaoImpl.getInstance(); 
  24.         User user = userDao.findUserByNameOrEmail(userNameOrEmail); 
  25.         if (user == null) { 
  26.             request.setAttribute("errorMsg", userNameOrEmail + ",不存在!"); 
  27.             request.getRequestDispatcher("/forgotPwdUI").forward(request, response); 
  28.             return
  29.         } 
  30.          
  31.         // 發送重新設置密碼的鏈接 
  32.         EmailUtils.sendResetPasswordEmail(user); 
  33.          
  34.         request.setAttribute("sendMailMsg", "您的申請已提交成功,請查看您的"+user.getEmail()+"郵箱。"); 
  35.          
  36.         request.getRequestDispatcher("/WEB-INF/pages/forgotPwdSuccess.jsp").forward(request, response); 
  37.     } 
  38.  
  39.     protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 
  40.         doGet(request, response); 
  41.     } 
package org.study.accountactivate.web.servlet;

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

import org.study.accountactivate.dao.UserDao;
import org.study.accountactivate.dao.impl.UserDaoImpl;
import org.study.accountactivate.domail.User;
import org.study.accountactivate.util.EmailUtils;

/**
 * 發送重設密碼申請的鏈接
 */
public class ForgotPwdServlet extends HttpServlet {
	
	private static final long serialVersionUID = 1L;

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		String userNameOrEmail = request.getParameter("userNameOrEmail");
		UserDao userDao = UserDaoImpl.getInstance();
		User user = userDao.findUserByNameOrEmail(userNameOrEmail);
		if (user == null) {
			request.setAttribute("errorMsg", userNameOrEmail + ",不存在!");
			request.getRequestDispatcher("/forgotPwdUI").forward(request, response);
			return;
		}
		
		// 發送重新設置密碼的鏈接
		EmailUtils.sendResetPasswordEmail(user);
		
		request.setAttribute("sendMailMsg", "您的申請已提交成功,請查看您的"+user.getEmail()+"郵箱。");
		
		request.getRequestDispatcher("/WEB-INF/pages/forgotPwdSuccess.jsp").forward(request, response);
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doGet(request, response);
	}
}

4、重新設置密碼的頁面

  1. <form action="${pageContext.request.contextPath}/resetPassword" method="post"> 
  2.     <span class="error" style="display: block;">${errors.passwordError}</span> 
  3.     用戶名:<input type="text" name="userName" value="${userName}" readonly="readonly"/><br/> 
  4.     新密碼:<input type="password" name="newPassword" /><span class="error">${errors.newPassword }</span><br/> 
  5.     確認新密碼:<input type="password" name="newPassword2"/><span class="error">${errors.newPassword2 }</span><br/> 
  6.     <input type="submit" value="修改" /> 
  7. </form> 
<form action="${pageContext.request.contextPath}/resetPassword" method="post">
	<span class="error" style="display: block;">${errors.passwordError}</span>
	用戶名:<input type="text" name="userName" value="${userName}" readonly="readonly"/><br/>
	新密碼:<input type="password" name="newPassword" /><span class="error">${errors.newPassword }</span><br/>
	確認新密碼:<input type="password" name="newPassword2"/><span class="error">${errors.newPassword2 }</span><br/>
	<input type="submit" value="修改" />
</form>

5、處理重新設置密碼請求的Servlet(ResetPasswordServlet)

  1. package org.study.accountactivate.web.servlet; 
  2.  
  3. import java.io.IOException; 
  4. import java.util.HashMap; 
  5. import java.util.Map; 
  6.  
  7. import javax.servlet.ServletException; 
  8. import javax.servlet.http.HttpServlet; 
  9. import javax.servlet.http.HttpServletRequest; 
  10. import javax.servlet.http.HttpServletResponse; 
  11.  
  12. import org.study.accountactivate.dao.UserDao; 
  13. import org.study.accountactivate.dao.impl.UserDaoImpl; 
  14. import org.study.accountactivate.domail.User; 
  15.  
  16. /**
  17. * 重新設置密碼
  18. */ 
  19. public class ResetPasswordServlet extends HttpServlet { 
  20.     private static final long serialVersionUID = 1L; 
  21.         
  22.     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 
  23.         String userName = request.getParameter("userName"); 
  24.         String newPassword = request.getParameter("newPassword"); 
  25.         String newPassword2 = request.getParameter("newPassword2"); 
  26.         Map<String,String> errors = new HashMap<String, String>(); 
  27.         if (newPassword == null || "".equals(newPassword)) { 
  28.             errors.put("newPassword", "新密碼不能爲空!"); 
  29.         } 
  30.          
  31.         if (newPassword2 == null || "".equals(newPassword2)) { 
  32.             errors.put("newPassword2", "確認新密碼不能爲空!"); 
  33.         } 
  34.          
  35.         if (!newPassword.equals(newPassword2)) { 
  36.             errors.put("passwordError", "兩次輸入的密碼不一致!"); 
  37.         } 
  38.          
  39.         if (!errors.isEmpty()) { 
  40.             request.setAttribute("errors", errors); 
  41.             request.getRequestDispatcher("/resetPasswordUI?userName=" + userName).forward(request, response); 
  42.             return
  43.         } 
  44.          
  45.         UserDao userDao = UserDaoImpl.getInstance(); 
  46.         User user = userDao.findUserByName(userName); 
  47.         user.setPassword(newPassword); 
  48.          
  49.         request.getRequestDispatcher("/WEB-INF/pages/resetPasswordSuccess.jsp").forward(request, response); 
  50.          
  51.     } 
  52.  
  53.     protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 
  54.         doGet(request, response); 
  55.     } 
package org.study.accountactivate.web.servlet;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.study.accountactivate.dao.UserDao;
import org.study.accountactivate.dao.impl.UserDaoImpl;
import org.study.accountactivate.domail.User;

/**
 * 重新設置密碼
 */
public class ResetPasswordServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
       
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		String userName = request.getParameter("userName");
		String newPassword = request.getParameter("newPassword");
		String newPassword2 = request.getParameter("newPassword2");
		Map<String,String> errors = new HashMap<String, String>();
		if (newPassword == null || "".equals(newPassword)) {
			errors.put("newPassword", "新密碼不能爲空!");
		}
		
		if (newPassword2 == null || "".equals(newPassword2)) {
			errors.put("newPassword2", "確認新密碼不能爲空!");
		}
		
		if (!newPassword.equals(newPassword2)) {
			errors.put("passwordError", "兩次輸入的密碼不一致!");
		}
		
		if (!errors.isEmpty()) {
			request.setAttribute("errors", errors);
			request.getRequestDispatcher("/resetPasswordUI?userName=" + userName).forward(request, response);
			return;
		}
		
		UserDao userDao = UserDaoImpl.getInstance();
		User user = userDao.findUserByName(userName);
		user.setPassword(newPassword);
		
		request.getRequestDispatcher("/WEB-INF/pages/resetPasswordSuccess.jsp").forward(request, response);
		
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doGet(request, response);
	}
}

帳戶激活操作流程:

1)、註冊頁面

 

2)、註冊成功頁面


3)、帳戶未激活,登錄後的界面


4)、前往郵箱中激活帳戶


5)、激活成功


6)、帳戶已激活,登錄後的界面



忘記密碼操作流程:

1)、登錄頁面(點擊“忘記密碼”鏈接,進入重設密碼頁面)

2、重設密碼申請頁面(輸入用戶名或郵箱,點擊“提交”按鈕)


3、重設密碼申請成功頁面


4、郵箱中重設密碼的鏈接


5、重新設置密碼頁面


6、密碼重新設置成功頁面


 

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