注册邮箱验证激活技术
一.先说思路
//1.数据库加三个字段,state:(0:未激活,1:激活成功),ActiCode:(放激活码),token_exptime(过期时间,用来验证激活邮件是否过期)
//2.用户填写资料,点击注册,插入数据成功,state字段默认是0,同时生成一个ActiCode(用传过来的邮箱、密码、和当前时间加密形成)也存入数据库
//3.发送邮件。。。提示用户登录邮箱激活。。。邮件中带一个激活成功页的URL,URL里有两个参数(1,用户ID,2:激活码)
//4.用户登录邮箱点击链接,来到处理激活的业务逻辑页面或Servlet,得到URL中两个参数,以这两个参数为条件查询数据库里的数据,如果有,取当前时间和之前存入数据库的过期时间作比较,看是否过期,过期,删除数据库中该条记录,并转到失败页面,没过期,查看链接传过来的激活码与数据库字段激活码是否一致,不一致,同样删除数据库中该条记录,并跳转到激活失败界面,一致,则将字段state为1,激活成功,转到激活成功页。。。
二、具体实现代码
1.首先,准备一个简单的测试页面<body> <div id="main" style="margin:0 auto;width:500px;"> <form id="reg" action="user.action?op=reg" method="post"> <p> E-mail:<input type="text" class="input" name="email" id="email"> </p> <p> 密 码:<input type="password" class="input" name="pwd" id="pwd"> </p> <p> <input type="submit" class="btn" value="提交注册" > </p> </form> </div> </body>
2.点击提交注册,来到user.action?op=reg,注意带的参数op指我要做的操作,用于后面的Servlet做判断该做什么操作,下面的代码完成了形成激活码、过期时间等表示当前注册用户的状态的信息存入数据库并发送邮件的过程。(邮件内容自定义,可以忽略我的)
package com.nh.web.servlets; import java.io.IOException; import java.io.PrintWriter; import java.sql.SQLException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.List; import java.util.UUID; import javax.naming.NamingException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.nh.dao.DBHelper; import com.nh.utils.Encrypt; import com.nh.utils.SendEmail; public class UserServlet extends CommonServlet { public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 取出op String op = request.getParameter("op"); // 判断op是什么,调用不同的方法做处理 try { if (op != null && !"".equals(op)) { if ("reg".equals(op)) { regOP(request, response); } } else { } } catch (Exception e) { e.printStackTrace(); response.sendRedirect("common/500.jsp"); } } private void regOP(HttpServletRequest request, HttpServletResponse response) throws IOException, SQLException, NamingException { // 1.数据库加两个字,state字段(0:未激活,1:激活成功),ActiCode:(放激活码) // 2.用户填写资料,插入数据成功,state字段默认是0,同时生成一个ActiCode也存入数据库 // 3.提示用户激活。。。发送邮件。。。邮件中带一个激活成功页的URL,URL里有两个参数(1,用户ID,2:激活码) // 4.用户点击链接,回到激活成功页。。。激活成功页的Load事件,得到两个参数,以这两个参数为条件查询数据库里的数据,如果有,修改字段state为1,反之。。提示激活失败,重新激活。。 String email=request.getParameter("email"); String pwd=Encrypt.md5(request.getParameter("pwd")); Calendar c = Calendar.getInstance(); //现在的时间(单位:毫秒) //TODO:时间换算问题,如何处理int和long之间的关系 long time = c.getTimeInMillis(); //创建激活码 String token=Encrypt.md5(email+pwd+time); //过期时间为24小时后 // int token_exptime=(int)(time+1000*60*60*24); String token_exptime=(time+1000*20)+""; //这里测试是用的20秒 String id=UUID.randomUUID().toString(); String sql="insert into tb_user(id,username,pwd,token,token_exptime,regtime,status) values (?,?,?,?,?,sysdate,0)"; List<Object> params=new ArrayList<Object>(); params.add(id); params.add(email); params.add(pwd); params.add(token); params.add(token_exptime); DBHelper db=new DBHelper(); int r=db.doUpdate(sql, params); //保存注册信息 if( r>0 ){ //发送邮件 ///邮件的内容 SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd"); StringBuffer sb=new StringBuffer("<div style=\"width:660px;overflow:hidden;border-bottom:1px solid #bdbdbe;\"><div style=\"height:52px;overflow:hidden;border:1px solid #464c51;background:#353b3f url(http://www.lofter.com/rsc/img/email/hdbg.png);\"><a href=\"http://www.lofter.com?mail=qbclickbynoticemail_20120626_01\" target=\"_blank\" style=\"display:block;width:144px;height:34px;margin:10px 0 0 20px;overflow:hidden;text-indent:-2000px;background:url(http://www.lofter.com/rsc/img/email/logo.png) no-repeat;\">LOFTER</a></div>"+"<div style=\"padding:24px 20px;\">您好,"+email+"<br/><br/>LOFTER是一款\"专注兴趣、分享创作\"的轻博客产品,旨在为\"热爱记录生活、追求时尚品质、崇尚自由空间\"的你,打造一个全新而定展示平台!<br/><br/>请点击下面链接激活账号,24小时生效,否则重新注册账号,链接只能使用一次,请尽快激活!</br>"); sb.append("<a href=\"http://localhost:8080/mailtest/emailcheck.action?op=activate&id="); sb.append(id); sb.append("&token="); sb.append(token); sb.append("\">http://localhost:8080/mailtest/emailcheck.action?op=activate&id="); sb.append(id); sb.append("&token="); sb.append(token); sb.append("</a>"+"<br/>如果以上链接无法点击,请把上面网页地址复制到浏览器地址栏中打开<br/><br/><br/>LOFTER,专注兴趣,分享创作<br/>"+sdf.format(new Date())+ "</div></div>" ); //发送邮件 SendEmail.send(email, sb.toString()); } response.sendRedirect("doEmail.action?op=emaillogin&email="+email+"&pwd="+pwd); } }
发送邮件的代码,这里需要导入javax.mail的包,即mail.jar,如果发件人邮箱是QQ邮箱还要去QQ邮箱开启smtp和其他两个协议,我这里用的163邮箱就不需要设置
package com.nh.utils; import java.util.Date; import java.util.Properties; import javax.mail.Authenticator; import javax.mail.Message; import javax.mail.MessagingException; import javax.mail.PasswordAuthentication; import javax.mail.Session; import javax.mail.Transport; import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeMessage; /** * * @author Qixuan.Chen */ public class SendEmail { public static final String HOST = "smtp.163.com"; // public static final String PROTOCOL = "smtp"; // public static final int PORT = 25; public static final String FROM = "xxxx@163.com";//发件人的email public static final String PWD = "xxxx";//发件人密码 /** * 获取Session * @return */ private static Session getSession() { Properties props = new Properties(); props.put("mail.smtp.host", HOST);//设置服务器地址 // props.put("mail.store.protocol" , PROTOCOL);//设置协议 // props.put("mail.smtp.port", PORT);//设置端口 props.put("mail.smtp.auth" , "true"); Authenticator authenticator = new Authenticator() { @Override protected PasswordAuthentication getPasswordAuthentication() { return new PasswordAuthentication(FROM, PWD); } }; Session session = Session.getDefaultInstance(props , authenticator); return session; } public static void send(String toEmail , String content) { Session session = getSession(); try { // System.out.println("--send--"+content); // Instantiate a message Message msg = new MimeMessage(session); //Set message attributes msg.setFrom(new InternetAddress(FROM)); InternetAddress[] address = {new InternetAddress(toEmail)}; msg.setRecipients(Message.RecipientType.TO, address); msg.setSubject("账号激活邮件"); msg.setSentDate(new Date()); msg.setContent(content , "text/html;charset=utf-8"); //Send the message Transport.send(msg); } catch (MessagingException mex) { mex.printStackTrace(); } } }
这是QQ邮箱设置,一般开启1、2、4
这是收到的激活邮件
根据用户所填邮箱跳转相应邮箱登录地址的代码
package com.nh.web.servlets; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class DoEmailLoginServlet extends CommonServlet { public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String op = request.getParameter("op"); // 判断op是什么,调用不同的方法做处理 try { if (op != null && !"".equals(op)) { if ("emaillogin".equals(op)) { emailloginOP(request, response); } } else { } } catch (Exception e) { e.printStackTrace(); response.sendRedirect("common/500.jsp"); } } private void emailloginOP(HttpServletRequest request, HttpServletResponse response) throws IOException { //判断用户邮箱是什么,跳到指定邮箱登陆界面 String email=request.getParameter("email"); //572480349@qq.com String pwd=request.getParameter("pwd"); String addrstr=email.split("@")[1]; //qq.com if( "qq.com".equals(addrstr)){ addrstr="https://mail.qq.com"; }else if( "163.com".equals(addrstr)){ addrstr="http://mail.163.com/"; }else if( "126.com".equals(addrstr)){ addrstr="http://www.126.com/"; }else if( "sina.com".equals(addrstr)){ addrstr="http://mail.sina.com.cn/"; }else if( "hotmail.com".equals(addrstr)){ addrstr="https://login.live.com"; } response.sendRedirect("emailaction.jsp?email="+email+"&pwd="+pwd+"&addrstr="+addrstr); } }
具体页面我就不一一给了,直接上激活验证代码吧
package com.nh.web.servlets; import java.io.IOException; import java.io.PrintWriter; import java.lang.reflect.InvocationTargetException; import java.sql.SQLException; import java.util.ArrayList; import java.util.Calendar; import java.util.List; import javax.naming.NamingException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.lofter.bean.User; import com.nh.dao.DBHelper; import com.nh.utils.DataExistAlreadyException; public class EmailActivateCheckServlet extends CommonServlet { public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 取出op String op = request.getParameter("op"); // 判断op是什么,调用不同的方法做处理 try { if (op != null && !"".equals(op)) { if( "activate".equals(op)){ activateOP(request,response); } } else { } } catch (Exception e) { e.printStackTrace(); response.sendRedirect("common/500.jsp"); } } private void activateOP(HttpServletRequest request, HttpServletResponse response) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, Exception { //获取参数token的值,即激活识别码。 //将它与数据表中的用户信息进行查询对比,如果有相应的数据集,判断是否过期,如果在有效期内则将对应的用户表中字段status设置1,即已激活,这样就完成了激活功能。 String id=request.getParameter("id"); String token=request.getParameter("token"); Calendar c = Calendar.getInstance(); //现在的时间(单位:毫秒) long curtime = c.getTimeInMillis(); String sql="select id,token_exptime,token,username,pwd from tb_user where status=0 and token=?"; List<Object> params=new ArrayList<Object>(); params.add( token ); DBHelper db=new DBHelper(); User u=db.findSingleObject(User.class, sql, params); String email=u.getUsername(); String pwd=u.getPwd(); if( u!=null ){ long token_exptime=Long.parseLong(u.getToken_exptime()); if( curtime>token_exptime ){ //激活码过期,先删除该用户记录,然后重新发送邮件 sql="delete from tb_user where id='"+u.getId()+"'"; db.doUpdate(sql, null); response.sendRedirect("actionfailer.jsp?email="+email+"&pwd="+pwd); // throw new DataExistAlreadyException("激活码已过期!"); return; }else{ //验证激活码是否正确 if( token.equals(u.getToken())){ //激活成功, //并更新用户的激活状态,为已激活 sql="update tb_user set status=1 where id='"+u.getId()+"'"; db.doUpdate(sql, null); response.sendRedirect("actionsuccess.jsp"); }else{ sql="delete from tb_user where id='"+u.getId()+"'"; db.doUpdate(sql, null); response.sendRedirect("actionfailer.jsp?email="+email+"&pwd="+pwd); return; // throw new DataExistAlreadyException("激活码不正确"); } } } } } package com.nh.web.servlets; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; public abstract class CommonServlet extends HttpServlet { private static final long serialVersionUID = 3893961453320250657L; private String saveFilePath=""; protected String basePath=""; @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doPost(req,resp); } @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { saveFilePath=req.getRealPath("/"); HttpSession session=req.getSession(); ServletContext application=session.getServletContext(); if( application.getAttribute("basePath")!=null ){ basePath=(String) application.getAttribute("basePath"); } super.service(req, resp); } } package com.lofter.bean; import java.io.Serializable; import java.util.Date; public class User implements Serializable { private static final long serialVersionUID = -1989259749641485708L; private String id; private String username; // --账户 private String pwd; // --密码 private String nickname; // --名称 private String autograph; // --个人签名 private String head; // --头像 private Date regtime; // --注册时间 private String token; // --账号激活码 private String token_exptime; // --激活码有效期 private Integer status; // --激活状态 ,0-未激活,1-已激活 public User() { super(); } public User(String id, String username, String pwd, String nickname, String autograph, String head, Date regtime, String token, String token_exptime, Integer status) { super(); this.id = id; this.username = username; this.pwd = pwd; this.nickname = nickname; this.autograph = autograph; this.head = head; this.regtime = regtime; this.token = token; this.token_exptime = token_exptime; this.status = status; } public String getId() { return id; } public void setId(String id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPwd() { return pwd; } public void setPwd(String pwd) { this.pwd = pwd; } public String getNickname() { return nickname; } public void setNickname(String nickname) { this.nickname = nickname; } public String getAutograph() { return autograph; } public void setAutograph(String autograph) { this.autograph = autograph; } public String getHead() { return head; } public void setHead(String head) { this.head = head; } public Date getRegtime() { return regtime; } public void setRegtime(Date regtime) { this.regtime = regtime; } public static long getSerialversionuid() { return serialVersionUID; } public String getToken() { return token; } public void setToken(String token) { this.token = token; } public String getToken_exptime() { return token_exptime; } public void setToken_exptime(String token_exptime) { this.token_exptime = token_exptime; } public Integer getStatus() { return status; } public void setStatus(Integer status) { this.status = status; } }