Explorar el Código

用户邮箱验证

Luxnk hace 7 años
padre
commit
3c3604c3f4

+ 7 - 0
conf/custom/mail.properties

@@ -0,0 +1,7 @@
+mail.HostName=smtp.163.com
+mail.SmtpPort=25
+mail.UserName=asd2864581@163.com
+mail.Password=Asd(3115799)
+mail.SSLOnConnect=false
+mail.From=asd2864581@163.com
+mail.charset=UTF-8

+ 18 - 0
conf/ioc/mail.js

@@ -0,0 +1,18 @@
+var ioc = {
+    emailAuthenticator: {
+        type: "org.apache.commons.mail.DefaultAuthenticator",
+        args: [{java: "$conf.get('mail.UserName')"}, {java: "$conf.get('mail.Password')"}]
+    },
+    htmlEmail: {
+        type: "org.apache.commons.mail.ImageHtmlEmail",
+        singleton: false,
+        fields: {
+            hostName: {java: "$conf.get('mail.HostName')"},
+            smtpPort: {java: "$conf.get('mail.SmtpPort')"},
+            authenticator: {refer: "emailAuthenticator"},
+            SSLOnConnect: {java: "$conf.get('mail.SSLOnConnect')"},
+            from: {java: "$conf.get('mail.From')"},
+            charset: {java: "$conf.get('mail.charset', 'UTF-8')"}
+        }
+    }
+}

+ 12 - 0
src/xyz/luxnk/lproject/MainSetup.java

@@ -1,5 +1,6 @@
 package xyz.luxnk.lproject;
 
+import org.apache.commons.mail.HtmlEmail;
 import org.nutz.dao.Dao;
 import org.nutz.dao.util.Daos;
 import org.nutz.el.opt.custom.CustomMake;
@@ -36,6 +37,17 @@ public class MainSetup implements Setup {
 
         // 获取NutQuartzCronJobFactory从而触发计划任务的初始化与启动
         ioc.get(NutQuartzCronJobFactory.class);
+
+        /*try {
+            HtmlEmail email = ioc.get(HtmlEmail.class);
+            email.setSubject("测试邮件发送");
+            email.setMsg("This is a test mail... :-)" + System.currentTimeMillis());
+            email.addTo("asd3115799@hotmail.com");
+            email.buildMimeMessage();
+            email.sendMimeMessage();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }*/
     }
 
     @Override

+ 7 - 0
src/xyz/luxnk/lproject/module/BaseModule.java

@@ -2,10 +2,17 @@ package xyz.luxnk.lproject.module;
 
 import org.nutz.dao.Dao;
 import org.nutz.ioc.loader.annotation.Inject;
+import org.nutz.lang.random.R;
+import xyz.luxnk.lproject.service.EmailService;
 
 public abstract class BaseModule {
 
     @Inject // 注入同名的一个ioc对象
     protected Dao dao;
 
+    @Inject
+    protected EmailService emailService;
+
+    protected byte[] emailKEY = R.sg(24).next().getBytes();
+
 }

+ 79 - 0
src/xyz/luxnk/lproject/module/UserProfileModule.java

@@ -1,10 +1,14 @@
 package xyz.luxnk.lproject.module;
 
+import org.nutz.dao.Chain;
+import org.nutz.dao.Cnd;
 import org.nutz.dao.DaoException;
 import org.nutz.dao.FieldFilter;
 import org.nutz.dao.util.Daos;
 import org.nutz.img.Images;
 import org.nutz.ioc.loader.annotation.IocBean;
+import org.nutz.lang.Strings;
+import org.nutz.lang.util.NutMap;
 import org.nutz.log.Log;
 import org.nutz.log.Logs;
 import org.nutz.mvc.Mvcs;
@@ -16,8 +20,10 @@ import org.nutz.mvc.impl.AdaptorErrorContext;
 import org.nutz.mvc.upload.TempFile;
 import org.nutz.mvc.upload.UploadAdaptor;
 import xyz.luxnk.lproject.bean.UserProfile;
+import xyz.luxnk.lproject.util.Toolkit;
 
 import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
 import java.awt.*;
 import java.awt.image.BufferedImage;
 import java.io.ByteArrayOutputStream;
@@ -150,4 +156,77 @@ public class UserProfileModule extends BaseModule {
         return profile.getAvatar();
     }
 
+    /**
+     * 向用户邮箱发送验证邮件<br />
+     * 注意, 因为emailKEY每次启动都是新的,所以重启Tomcat后,老的验证邮件就无效了哦. 真正用到时候,一般会存到一个文件或者数据库里面去
+     * @param userId
+     * @param req
+     * @return
+     */
+    @At("/active/mail")
+    @POST
+    public Object activeMail(@Attr(scope = Scope.SESSION, value = "me")String userId, HttpServletRequest req) {
+        NutMap re = new NutMap();
+        UserProfile profile = get(userId);
+        if (Strings.isBlank(profile.getEmail())) {
+            return re.setv("ok", false).setv("msg", "你还没有填邮箱啊!");
+        }
+        String token = String.format("%s,%s,%s", userId, profile.getEmail(), System.currentTimeMillis());
+        token = Toolkit._3DES_encode(emailKEY, token.getBytes());
+        String url = req.getRequestURL() + "?token=" + token;
+        String html = "<div>如果无法点击,请复制链接到浏览器中打开<p />验证链接 %s</div>";
+        html = String.format(html, url, url);
+        try {
+            boolean ok = emailService.send(profile.getEmail(), "XXX 验证邮件 by Luxnk", html);
+            if (!ok) {
+                return re.setv("ok", false).setv("msg", "发送失败");
+            }
+        } catch (Throwable e) {
+            log.debug("发送邮件失败", e);
+            return re.setv("ok", false).setv("msg", "发送失败");
+        }
+        return re.setv("ok", true);
+    }
+
+    /**
+     * 验证用户邮箱
+     * @param token
+     * @param session
+     * @return
+     */
+    @Filters // 不需要登录
+    @At("/active/mail")
+    @GET
+    @Ok("raw")  // 为了简单起见,这里直接显示验证结果就好了
+    public String activeMailCallback(@Param("token")String token, HttpSession session) {
+        if (Strings.isBlank(token)) {
+            return "请不要直接访问这个链接!!!";
+        }
+        if (token.length() < 10) {
+            return "非法token";
+        }
+        try {
+            token = Toolkit._3DES_decode(emailKEY, Toolkit.hexstr2bytearray(token));
+            if (token == null)
+                return "非法token";
+            String[] tmp = token.split(",", 3);
+            if (tmp.length != 3 || tmp[0].length() == 0 || tmp[1].length() == 0 || tmp[2].length() == 0)
+                return "非法token";
+            long time = Long.parseLong(tmp[2]);
+            if (System.currentTimeMillis() - time > 10 * 60 * 1000) {
+                return "该验证链接已经超时";
+            }
+            String userId = tmp[0];
+            Cnd cnd = Cnd.where("userId", "=", userId).and("email", "=", tmp[1]);
+            int re = dao.update(UserProfile.class, Chain.make("emailChecked", true), cnd);
+            if (re == 1) {
+                return "验证成功";
+            }
+            return "验证失败!请重新验证!!";
+        } catch (Throwable e) {
+            log.debug("检查token时出错", e);
+            return "非法token";
+        }
+    }
+
 }

+ 7 - 0
src/xyz/luxnk/lproject/service/EmailService.java

@@ -0,0 +1,7 @@
+package xyz.luxnk.lproject.service;
+
+public interface EmailService {
+
+    boolean send(String to, String subject, String html);
+
+}

+ 33 - 0
src/xyz/luxnk/lproject/service/EmailServiceImpl.java

@@ -0,0 +1,33 @@
+package xyz.luxnk.lproject.service;
+
+import org.apache.commons.mail.HtmlEmail;
+import org.nutz.ioc.Ioc;
+import org.nutz.ioc.loader.annotation.Inject;
+import org.nutz.ioc.loader.annotation.IocBean;
+import org.nutz.log.Log;
+import org.nutz.log.Logs;
+
+@IocBean(name = "emailService")
+public class EmailServiceImpl implements EmailService {
+
+    private static final Log log = Logs.get();
+
+    @Inject("refer:$ioc")
+    protected Ioc ioc;
+
+    @Override
+    public boolean send(String to, String subject, String html) {
+        try {
+            HtmlEmail email = ioc.get(HtmlEmail.class);
+            email.setSubject(subject);
+            email.setHtmlMsg(html);
+            email.addTo(to);
+            email.buildMimeMessage();
+            email.sendMimeMessage();
+            return true;
+        } catch (Throwable e) {
+            log.info("send email fail", e);
+            return false;
+        }
+    }
+}

+ 19 - 0
web/WEB-INF/jsp/user/profile.jsp

@@ -47,6 +47,25 @@
             </div>
             <div>
                 邮箱验证状态:<c:out value="${obj.emailChecked}"></c:out><p />
+                <c:if test="${!obj.emailChecked}">
+                    <button type="button" onclick="send_email_check(); return false;">发送验证邮件</button>
+                    <script>
+                        function send_email_check() {
+                            $.ajax({
+                                url: base + "/user/profile/active/mail",
+                                type: "POST",
+                                dataType: "json",
+                                success: function (data) {
+                                    if (data.ok) {
+                                        alert("发送成功");
+                                    } else {
+                                        alert(data.msg);
+                                    }
+                                }
+                            })
+                        }
+                    </script>
+                </c:if>
             </div>
             <div>
                 性别:<input name="gender" value="${obj.gender}"><p />

BIN
web/WEB-INF/lib/commons-email-1.3.3.jar


BIN
web/WEB-INF/lib/javax.mail-1.5.2.jar