新增找回密码功能,支持通过手机号、邮箱、保密问题找回。
This commit is contained in:
@@ -3,13 +3,10 @@
|
||||
*/
|
||||
package com.jeesite.common.mail;
|
||||
|
||||
import org.apache.commons.mail.HtmlEmail;
|
||||
|
||||
import com.jeesite.common.io.PropertiesUtils;
|
||||
|
||||
/**
|
||||
* 发送电子邮件
|
||||
*/
|
||||
@Deprecated
|
||||
public class EmailUtils {
|
||||
|
||||
/**
|
||||
@@ -19,14 +16,9 @@ public class EmailUtils {
|
||||
* @param content 内容
|
||||
* @return
|
||||
*/
|
||||
@Deprecated
|
||||
public static boolean sendEmail(String toAddress, String subject, String content) {
|
||||
PropertiesUtils loader = PropertiesUtils.getInstance();
|
||||
String fromAddress = loader.getProperty("msg.email.fromAddress");
|
||||
String fromPassword = loader.getProperty("msg.email.fromPassword");
|
||||
String fromHostName = loader.getProperty("msg.email.fromHostName");
|
||||
String sslOnConnect = loader.getProperty("msg.email.sslOnConnect", "false");
|
||||
String sslSmtpPort = loader.getProperty("msg.email.sslSmtpPort");
|
||||
return sendEmail(fromAddress, fromPassword, fromHostName, sslOnConnect, sslSmtpPort, toAddress, subject, content);
|
||||
return com.jeesite.common.msg.EmailUtils.send(toAddress, subject, content);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -36,296 +28,10 @@ public class EmailUtils {
|
||||
* @param content 内容
|
||||
* @return
|
||||
*/
|
||||
@Deprecated
|
||||
public static boolean sendEmail(String fromAddress, String fromPassword, String fromHostName,
|
||||
String sslOnConnect, String sslSmtpPort, String toAddress, String subject, String content) {
|
||||
try {
|
||||
HtmlEmail htmlEmail = new HtmlEmail();
|
||||
// 发送地址
|
||||
htmlEmail.setFrom(fromAddress);
|
||||
// 密码校验
|
||||
htmlEmail.setAuthentication(fromAddress, fromPassword);
|
||||
// 发送服务器协议
|
||||
htmlEmail.setHostName(fromHostName);
|
||||
|
||||
// SSL
|
||||
if ("true".equals(sslOnConnect)) {
|
||||
htmlEmail.setSSLOnConnect(true);
|
||||
htmlEmail.setSslSmtpPort(sslSmtpPort);
|
||||
}
|
||||
|
||||
// 接收地址
|
||||
htmlEmail.addTo(toAddress);
|
||||
|
||||
// 标题
|
||||
htmlEmail.setSubject(subject);
|
||||
// 内容
|
||||
htmlEmail.setMsg(content);
|
||||
|
||||
// 其他信息
|
||||
htmlEmail.setCharset("utf-8");
|
||||
|
||||
// 发送
|
||||
htmlEmail.send();
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
|
||||
return com.jeesite.common.msg.EmailUtils.send(fromAddress, fromPassword, fromHostName, sslOnConnect, sslSmtpPort, toAddress, subject, content);
|
||||
}
|
||||
|
||||
// // private static final String smtphost = "192.168.1.70";
|
||||
// private static final String from = "thinkgem@163.com";
|
||||
// private static final String fromName = "测试公司";
|
||||
// private static final String charSet = "utf-8";
|
||||
// private static final String username = "thinkgem@163.com";
|
||||
// private static final String password = "123456";
|
||||
//
|
||||
// private static Map<String, String> hostMap = new HashMap<String, String>();
|
||||
// static {
|
||||
// // 126
|
||||
// hostMap.put("smtp.126", "smtp.126.com");
|
||||
// // qq
|
||||
// hostMap.put("smtp.qq", "smtp.qq.com");
|
||||
//
|
||||
// // 163
|
||||
// hostMap.put("smtp.163", "smtp.163.com");
|
||||
//
|
||||
// // sina
|
||||
// hostMap.put("smtp.sina", "smtp.sina.com.cn");
|
||||
//
|
||||
// // tom
|
||||
// hostMap.put("smtp.tom", "smtp.tom.com");
|
||||
//
|
||||
// // 263
|
||||
// hostMap.put("smtp.263", "smtp.263.net");
|
||||
//
|
||||
// // yahoo
|
||||
// hostMap.put("smtp.yahoo", "smtp.mail.yahoo.com");
|
||||
//
|
||||
// // hotmail
|
||||
// hostMap.put("smtp.hotmail", "smtp.live.com");
|
||||
//
|
||||
// // gmail
|
||||
// hostMap.put("smtp.gmail", "smtp.gmail.com");
|
||||
// hostMap.put("smtp.port.gmail", "465");
|
||||
// }
|
||||
//
|
||||
// public static String getHost(String email) throws Exception {
|
||||
// Pattern pattern = Pattern.compile("\\w+@(\\w+)(\\.\\w+){1,2}");
|
||||
// Matcher matcher = pattern.matcher(email);
|
||||
// String key = "unSupportEmail";
|
||||
// if (matcher.find()) {
|
||||
// key = "smtp." + matcher.group(1);
|
||||
// }
|
||||
// if (hostMap.containsKey(key)) {
|
||||
// return hostMap.get(key);
|
||||
// } else {
|
||||
// throw new Exception("unSupportEmail");
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// public static int getSmtpPort(String email) throws Exception {
|
||||
// Pattern pattern = Pattern.compile("\\w+@(\\w+)(\\.\\w+){1,2}");
|
||||
// Matcher matcher = pattern.matcher(email);
|
||||
// String key = "unSupportEmail";
|
||||
// if (matcher.find()) {
|
||||
// key = "smtp.port." + matcher.group(1);
|
||||
// }
|
||||
// if (hostMap.containsKey(key)) {
|
||||
// return Integer.parseInt(hostMap.get(key));
|
||||
// } else {
|
||||
// return 25;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 发送模板邮件
|
||||
// *
|
||||
// * @param toMailAddr 收信人地址
|
||||
// * @param subject email主题
|
||||
// * @param templatePath 模板地址
|
||||
// * @param map 模板map
|
||||
// */
|
||||
// public static void sendFtlMail(String toMailAddr, String subject, String templatePath, Map<String, Object> map) {
|
||||
// Template template = null;
|
||||
// Configuration freeMarkerConfig = null;
|
||||
// HtmlEmail hemail = new HtmlEmail();
|
||||
// try {
|
||||
// hemail.setHostName(getHost(from));
|
||||
// hemail.setSmtpPort(getSmtpPort(from));
|
||||
// hemail.setCharset(charSet);
|
||||
// hemail.addTo(toMailAddr);
|
||||
// hemail.setFrom(from, fromName);
|
||||
// hemail.setAuthentication(username, password);
|
||||
// hemail.setSubject(subject);
|
||||
// freeMarkerConfig = new Configuration();
|
||||
// freeMarkerConfig.setDirectoryForTemplateLoading(new File(getFilePath()));
|
||||
// // 获取模板
|
||||
// template = freeMarkerConfig.getTemplate(getFileName(templatePath), new Locale("Zh_cn"), "UTF-8");
|
||||
// // 模板内容转换为string
|
||||
// String htmlText = FreeMarkers.renderTemplate(template, map);
|
||||
// System.out.println(htmlText);
|
||||
// hemail.setMsg(htmlText);
|
||||
// hemail.send();
|
||||
// System.out.println("email send true!");
|
||||
// } catch (Exception e) {
|
||||
// e.printStackTrace();
|
||||
// System.out.println("email send error!");
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 发送普通邮件
|
||||
// *
|
||||
// * @param toMailAddr 收信人地址
|
||||
// * @param subject email主题
|
||||
// * @param message 发送email信息
|
||||
// */
|
||||
// public static void sendCommonMail(String toMailAddr, String subject, String message) {
|
||||
// HtmlEmail hemail = new HtmlEmail();
|
||||
// try {
|
||||
// hemail.setHostName(getHost(from));
|
||||
// hemail.setSmtpPort(getSmtpPort(from));
|
||||
// hemail.setCharset(charSet);
|
||||
// hemail.addTo(toMailAddr);
|
||||
// hemail.setFrom(from, fromName);
|
||||
// hemail.setAuthentication(username, password);
|
||||
// hemail.setSubject(subject);
|
||||
// hemail.setMsg(message);
|
||||
// hemail.send();
|
||||
// System.out.println("email send true!");
|
||||
// } catch (Exception e) {
|
||||
// e.printStackTrace();
|
||||
// System.out.println("email send error!");
|
||||
// }
|
||||
//
|
||||
// }
|
||||
//
|
||||
// public static String getHtmlText(String templatePath, Map<String, Object> map) {
|
||||
// Template template = null;
|
||||
// String htmlText = "";
|
||||
// try {
|
||||
// Configuration freeMarkerConfig = null;
|
||||
// freeMarkerConfig = new Configuration();
|
||||
// freeMarkerConfig.setDirectoryForTemplateLoading(new File(getFilePath()));
|
||||
// // 获取模板
|
||||
// template = freeMarkerConfig.getTemplate(getFileName(templatePath), new Locale("Zh_cn"), "UTF-8");
|
||||
// // 模板内容转换为string
|
||||
// htmlText = FreeMarkers.renderTemplate(template, map);
|
||||
// System.out.println(htmlText);
|
||||
// } catch (Exception e) {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
// return htmlText;
|
||||
// }
|
||||
//
|
||||
// private static String getFilePath() {
|
||||
// String path = getAppPath(SendMailUtil.class);
|
||||
// path = path + File.separator + "mailtemplate" + File.separator;
|
||||
// path = path.replace("\\", "/");
|
||||
// System.out.println(path);
|
||||
// return path;
|
||||
// }
|
||||
//
|
||||
// private static String getFileName(String path) {
|
||||
// path = path.replace("\\", "/");
|
||||
// System.out.println(path);
|
||||
// return path.substring(path.lastIndexOf("/") + 1);
|
||||
// }
|
||||
//
|
||||
// // @SuppressWarnings("unchecked")
|
||||
// public static String getAppPath(Class<?> cls) {
|
||||
// // 检查用户传入的参数是否为空
|
||||
// if (cls == null)
|
||||
// throw new java.lang.IllegalArgumentException("参数不能为空!");
|
||||
// ClassLoader loader = cls.getClassLoader();
|
||||
// // 获得类的全名,包括包名
|
||||
// String clsName = cls.getName() + ".class";
|
||||
// // 获得传入参数所在的包
|
||||
// Package pack = cls.getPackage();
|
||||
// String path = "";
|
||||
// // 如果不是匿名包,将包名转化为路径
|
||||
// if (pack != null) {
|
||||
// String packName = pack.getName();
|
||||
// // 此处简单判定是否是Java基础类库,防止用户传入JDK内置的类库
|
||||
// if (packName.startsWith("java.") || packName.startsWith("javax."))
|
||||
// throw new java.lang.IllegalArgumentException("不要传送系统类!");
|
||||
// // 在类的名称中,去掉包名的部分,获得类的文件名
|
||||
// clsName = clsName.substring(packName.length() + 1);
|
||||
// // 判定包名是否是简单包名,如果是,则直接将包名转换为路径,
|
||||
// if (packName.indexOf(".") < 0)
|
||||
// path = packName + "/";
|
||||
// else {// 否则按照包名的组成部分,将包名转换为路径
|
||||
// int start = 0, end = 0;
|
||||
// end = packName.indexOf(".");
|
||||
// while (end != -1) {
|
||||
// path = path + packName.substring(start, end) + "/";
|
||||
// start = end + 1;
|
||||
// end = packName.indexOf(".", start);
|
||||
// }
|
||||
// path = path + packName.substring(start) + "/";
|
||||
// }
|
||||
// }
|
||||
// // 调用ClassLoader的getResource方法,传入包含路径信息的类文件名
|
||||
// java.net.URL url = loader.getResource(path + clsName);
|
||||
// // 从URL对象中获取路径信息
|
||||
// String realPath = url.getPath();
|
||||
// // 去掉路径信息中的协议名"file:"
|
||||
// int pos = realPath.indexOf("file:");
|
||||
// if (pos > -1)
|
||||
// realPath = realPath.substring(pos + 5);
|
||||
// // 去掉路径信息最后包含类文件信息的部分,得到类所在的路径
|
||||
// pos = realPath.indexOf(path + clsName);
|
||||
// realPath = realPath.substring(0, pos - 1);
|
||||
// // 如果类文件被打包到JAR等文件中时,去掉对应的JAR等打包文件名
|
||||
// if (realPath.endsWith("!"))
|
||||
// realPath = realPath.substring(0, realPath.lastIndexOf("/"));
|
||||
// /*------------------------------------------------------------
|
||||
// ClassLoader的getResource方法使用了utf-8对路径信息进行了编码,当路径
|
||||
// 中存在中文和空格时,他会对这些字符进行转换,这样,得到的往往不是我们想要
|
||||
// 的真实路径,在此,调用了URLDecoder的decode方法进行解码,以便得到原始的
|
||||
// 中文及空格路径
|
||||
// -------------------------------------------------------------*/
|
||||
// try {
|
||||
// realPath = java.net.URLDecoder.decode(realPath, "utf-8");
|
||||
// } catch (Exception e) {
|
||||
// throw new RuntimeException(e);
|
||||
// }
|
||||
// System.out.println("realPath----->" + realPath);
|
||||
// return realPath;
|
||||
// }
|
||||
//
|
||||
// // private static File getFile(String path){
|
||||
// // File file =
|
||||
// // SendMail.class.getClassLoader().getResource("mailtemplate/test.ftl").getFile();
|
||||
// // return file;
|
||||
// // }
|
||||
// //
|
||||
//
|
||||
// public static void main(String[] args) {
|
||||
// // HtmlEmail hemail = new HtmlEmail();
|
||||
// // try {
|
||||
// // hemail.setHostName("smtp.exmail.qq.com");
|
||||
// // hemail.setCharset("utf-8");
|
||||
// // hemail.addTo("test@qq.com");
|
||||
// // hemail.setFrom("test@qq.com", "test");
|
||||
// // hemail.setAuthentication("test@test.com", "test@aa");
|
||||
// // hemail.setSubject("sendemail test!");
|
||||
// // hemail.setMsg("<a href=\"http://www.google.cn\">谷歌</a><br/>");
|
||||
// // hemail.send();
|
||||
// // System.out.println("email send true!");
|
||||
// // } catch (Exception e) {
|
||||
// // e.printStackTrace();
|
||||
// // System.out.println("email send error!");
|
||||
// // }
|
||||
// Map<String, Object> map = new HashMap<String, Object>();
|
||||
// map.put("subject", "测试标题");
|
||||
// map.put("content", "测试 内容");
|
||||
// String templatePath = "mailtemplate/test.ftl";
|
||||
// sendFtlMail("test@163.com", "sendemail test!", templatePath, map);
|
||||
//
|
||||
// // System.out.println(getFileName("mailtemplate/test.ftl"));
|
||||
// }
|
||||
|
||||
}
|
||||
80
common/src/main/java/com/jeesite/common/msg/EmailUtils.java
Normal file
80
common/src/main/java/com/jeesite/common/msg/EmailUtils.java
Normal file
@@ -0,0 +1,80 @@
|
||||
/**
|
||||
* Copyright (c) 2013-Now http://jeesite.com All rights reserved.
|
||||
*/
|
||||
package com.jeesite.common.msg;
|
||||
|
||||
import org.apache.commons.mail.HtmlEmail;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.jeesite.common.io.PropertiesUtils;
|
||||
|
||||
/**
|
||||
* 发送电子邮件
|
||||
*/
|
||||
public class EmailUtils {
|
||||
|
||||
private final static Logger logger = LoggerFactory.getLogger(EmailUtils.class);
|
||||
|
||||
/**
|
||||
* 发送邮件
|
||||
* @param toAddress 接收地址
|
||||
* @param subject 标题
|
||||
* @param content 内容
|
||||
* @return
|
||||
*/
|
||||
public static boolean send(String toAddress, String subject, String content) {
|
||||
PropertiesUtils loader = PropertiesUtils.getInstance();
|
||||
String fromAddress = loader.getProperty("msg.email.fromAddress");
|
||||
String fromPassword = loader.getProperty("msg.email.fromPassword");
|
||||
String fromHostName = loader.getProperty("msg.email.fromHostName");
|
||||
String sslOnConnect = loader.getProperty("msg.email.sslOnConnect", "false");
|
||||
String sslSmtpPort = loader.getProperty("msg.email.sslSmtpPort");
|
||||
return send(fromAddress, fromPassword, fromHostName, sslOnConnect, sslSmtpPort, toAddress, subject, content);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送邮件
|
||||
* @param toAddress 接收地址
|
||||
* @param subject 标题
|
||||
* @param content 内容
|
||||
* @return
|
||||
*/
|
||||
public static boolean send(String fromAddress, String fromPassword, String fromHostName,
|
||||
String sslOnConnect, String sslSmtpPort, String toAddress, String subject, String content) {
|
||||
try {
|
||||
HtmlEmail htmlEmail = new HtmlEmail();
|
||||
// 发送地址
|
||||
htmlEmail.setFrom(fromAddress);
|
||||
// 密码校验
|
||||
htmlEmail.setAuthentication(fromAddress, fromPassword);
|
||||
// 发送服务器协议
|
||||
htmlEmail.setHostName(fromHostName);
|
||||
|
||||
// SSL
|
||||
if ("true".equals(sslOnConnect)) {
|
||||
htmlEmail.setSSLOnConnect(true);
|
||||
htmlEmail.setSslSmtpPort(sslSmtpPort);
|
||||
}
|
||||
|
||||
// 接收地址
|
||||
htmlEmail.addTo(toAddress);
|
||||
|
||||
// 标题
|
||||
htmlEmail.setSubject(subject);
|
||||
// 内容
|
||||
htmlEmail.setMsg(content);
|
||||
|
||||
// 其他信息
|
||||
htmlEmail.setCharset("utf-8");
|
||||
|
||||
// 发送
|
||||
htmlEmail.send();
|
||||
return true;
|
||||
} catch (Exception ex) {
|
||||
logger.error(ex.getMessage(), ex);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -18,10 +18,10 @@ import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import com.jeesite.common.collect.MapUtils;
|
||||
import com.jeesite.common.config.Global;
|
||||
import com.jeesite.common.lang.StringUtils;
|
||||
import com.jeesite.common.msg.EmailUtils;
|
||||
import com.jeesite.common.msg.SmsUtils;
|
||||
import com.jeesite.common.service.ServiceException;
|
||||
import com.jeesite.common.web.BaseController;
|
||||
import com.jeesite.modules.msg.entity.MsgPush;
|
||||
import com.jeesite.modules.msg.utils.MsgPushUtils;
|
||||
import com.jeesite.modules.sys.entity.User;
|
||||
import com.jeesite.modules.sys.service.UserService;
|
||||
import com.jeesite.modules.sys.utils.UserUtils;
|
||||
@@ -49,21 +49,21 @@ public class AccountController extends BaseController{
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取短信、邮件验证码
|
||||
* 获取找回密码短信、邮件验证码
|
||||
* @param validCode 图片验证码,防止重复机器人。
|
||||
* @param validType 验证方式:mobile、email
|
||||
*/
|
||||
@PostMapping(value = "getValidCode")
|
||||
@PostMapping(value = "getFpValidCode")
|
||||
@ResponseBody
|
||||
public String getValidCode(User user, String validCode, String validType, HttpServletRequest request) {
|
||||
public String getFpValidCode(User user, String validCode, String validType, HttpServletRequest request) {
|
||||
// 校验图片验证码,防止重复机器人。
|
||||
if (!ValidCodeUtils.validate(request, validCode)){
|
||||
return renderResult(Global.FALSE, "验证码不正确或已失效!");
|
||||
return renderResult(Global.FALSE, "图片验证码不正确或已失效,请点击图片刷新!");
|
||||
}
|
||||
if (!"mobile".equals(validType) && !"email".equals(validType)){
|
||||
return renderResult(Global.FALSE, "非法操作。");
|
||||
}
|
||||
User u = userService.getByLoginCode(user);
|
||||
User u = UserUtils.getByLoginCode(user.getLoginCode());
|
||||
if(u == null){
|
||||
return renderResult(Global.FALSE, "登录账号不正确!");
|
||||
}
|
||||
@@ -106,17 +106,25 @@ public class AccountController extends BaseController{
|
||||
String validCode = (String)UserUtils.getCache("fpValidCode");
|
||||
Date date = (Date)UserUtils.getCache("fpLastDate");
|
||||
|
||||
// 一同验证保存的用户名和验证码是否正确(如果只校验验证码,不验证用户名,则会有获取验证码后修改用户名的漏洞)
|
||||
if (!(userCode != null && loginCode != null && loginCode.equals(user.getLoginCode()))){
|
||||
return renderResult(Global.FALSE, "请重新获取验证码!");
|
||||
}
|
||||
|
||||
// 清理验证码,验证码只允许使用一次。
|
||||
UserUtils.removeCache("fpUserCode");
|
||||
UserUtils.removeCache("fpLoginCode");
|
||||
UserUtils.removeCache("fpValidCode");
|
||||
UserUtils.removeCache("fpLastDate");
|
||||
|
||||
// 验证码是否超时
|
||||
boolean isTimeout = true;
|
||||
String validTime = Global.getConfig("sys.account.validCodeTimeout", "10"); //验证码有效时间(单位分钟,0表示不限制,默认值10)
|
||||
if("0".equals(validTime) || (date != null && (System.currentTimeMillis()-date.getTime())/(1000L) < 60*Long.parseLong(validTime))){
|
||||
isTimeout = false;
|
||||
}
|
||||
|
||||
// 一同验证保存的用户名和验证码是否正确(如果只校验验证码,不验证用户名,则会有获取验证码后修改用户名的漏洞)
|
||||
if (!(userCode != null && loginCode != null && loginCode.equals(user.getLoginCode())
|
||||
&& validCode != null && validCode.equals(fpValidCode) && !isTimeout)){
|
||||
return renderResult(Global.FALSE, "验证码不正确或已失效!");
|
||||
if (!(validCode != null && validCode.equals(fpValidCode) && !isTimeout)){
|
||||
return renderResult(Global.FALSE, "验证码不正确或已失效,请重新获取验证码!");
|
||||
}
|
||||
|
||||
// 更新为新密码。
|
||||
@@ -125,12 +133,6 @@ public class AccountController extends BaseController{
|
||||
}catch(ServiceException se){
|
||||
return renderResult(Global.FALSE, se.getMessage());
|
||||
}
|
||||
|
||||
// 修改密码成功后清理验证码,验证码只允许使用一次。
|
||||
UserUtils.removeCache("fpUserCode");
|
||||
UserUtils.removeCache("fpLoginCode");
|
||||
UserUtils.removeCache("fpValidCode");
|
||||
UserUtils.removeCache("fpLastDate");
|
||||
return renderResult(Global.TRUE, "恭喜你,您的账号 "+loginCode+" 密码修改成功!");
|
||||
}
|
||||
|
||||
@@ -143,13 +145,26 @@ public class AccountController extends BaseController{
|
||||
public String getPwdQuestion(User user, String validCode, HttpServletRequest request) {
|
||||
// 校验图片验证码,防止重复机器人。
|
||||
if (!ValidCodeUtils.validate(request, validCode)){
|
||||
return renderResult(Global.FALSE, "验证码不正确或已失效!");
|
||||
return renderResult(Global.FALSE, "图片验证码不正确或已失效,请点击图片刷新!");
|
||||
}
|
||||
// 账号是否存在验证
|
||||
User u = userService.getByLoginCode(user);
|
||||
User u = UserUtils.getByLoginCode(user.getLoginCode());
|
||||
if (u == null){
|
||||
return renderResult(Global.FALSE, "登录账号不正确!");
|
||||
}
|
||||
// 操作是否频繁验证, 如果离上次获取验证码小于20秒,则提示操作频繁。
|
||||
Date date = (Date)UserUtils.getCache("fpLastDate");
|
||||
if (date != null && (System.currentTimeMillis()-date.getTime())/(1000L) < 20L){
|
||||
return renderResult(Global.FALSE, "您当前操作太频繁,请稍等一会再操作!");
|
||||
}else{
|
||||
UserUtils.putCache("fpLastDate", new Date());
|
||||
}
|
||||
|
||||
// 未设置密保
|
||||
if (StringUtils.isAnyBlank(u.getPwdQuestion(), u.getPwdQuestion2(), u.getPwdQuestion3())){
|
||||
return renderResult(Global.FALSE, "该账号未设置密保问题!");
|
||||
}
|
||||
|
||||
// 获取保密问题,并缓存
|
||||
Map<String, String> data = MapUtils.newHashMap();
|
||||
data.put("pwdQuestion", u.getPwdQuestion());
|
||||
@@ -171,9 +186,18 @@ public class AccountController extends BaseController{
|
||||
public String savePwdByPwdQuestion(User user, HttpServletRequest request) {
|
||||
String userCode = (String)UserUtils.getCache("fpUserCode");
|
||||
String loginCode = (String)UserUtils.getCache("fpLoginCode");
|
||||
User u = userService.getByLoginCode(user);
|
||||
|
||||
// 一同验证保存的用户名和验证码是否正确(如果只校验验证码,不验证用户名,则会有获取验证码后修改用户名的漏洞)
|
||||
if (!(userCode != null && loginCode != null && loginCode.equals(user.getLoginCode()))){
|
||||
return renderResult(Global.FALSE, "请重新获取保密问题!");
|
||||
}
|
||||
|
||||
// 清理保密问题,每次获取只允许使用一次。
|
||||
UserUtils.removeCache("fpUserCode");
|
||||
UserUtils.removeCache("fpLoginCode");
|
||||
|
||||
// 验证三个密保问题是否正确。
|
||||
User u = UserUtils.getByLoginCode(user.getLoginCode());
|
||||
if (!(u != null && loginCode.equals(user.getLoginCode())
|
||||
&& UserService.validatePassword(user.getPwdQuestionAnswer(), u.getPwdQuestionAnswer())
|
||||
&& UserService.validatePassword(user.getPwdQuestionAnswer2(), u.getPwdQuestionAnswer2())
|
||||
@@ -187,10 +211,6 @@ public class AccountController extends BaseController{
|
||||
}catch(ServiceException se){
|
||||
return renderResult(Global.FALSE, se.getMessage());
|
||||
}
|
||||
|
||||
// 验证成功后清理缓存。
|
||||
UserUtils.removeCache("fpUserCode");
|
||||
UserUtils.removeCache("fpLoginCode");
|
||||
return renderResult(Global.TRUE, "验证通过");
|
||||
}
|
||||
|
||||
@@ -199,7 +219,6 @@ public class AccountController extends BaseController{
|
||||
* @param user 用户信息参数
|
||||
*/
|
||||
@RequestMapping(value = "registerUser")
|
||||
@ResponseBody
|
||||
public String registerUser(User user, HttpServletRequest request) {
|
||||
return "modules/sys/account/registerUser";
|
||||
}
|
||||
@@ -209,12 +228,12 @@ public class AccountController extends BaseController{
|
||||
* @param user 用户信息参数
|
||||
* @param validType 验证方式:mobile、email
|
||||
*/
|
||||
@PostMapping(value = "getRegisterUserValidCode")
|
||||
@PostMapping(value = "getRegValidCode")
|
||||
@ResponseBody
|
||||
public String getRegisterUserValidCode(User user, String validCode, String validType, HttpServletRequest request) {
|
||||
public String getRegValidCode(User user, String validCode, String validType, HttpServletRequest request) {
|
||||
// 校验图片验证码,防止重复机器人。
|
||||
if (!ValidCodeUtils.validate(request, validCode)){
|
||||
return renderResult(Global.FALSE, "验证码不正确或已失效!");
|
||||
return renderResult(Global.FALSE, "图片验证码不正确或已失效,请点击图片刷新!");
|
||||
}
|
||||
if (!"mobile".equals(validType) && !"email".equals(validType)){
|
||||
return renderResult(Global.FALSE, "非法操作。");
|
||||
@@ -238,7 +257,7 @@ public class AccountController extends BaseController{
|
||||
UserUtils.putCache("regLastDate", new Date());
|
||||
}
|
||||
// 验证用户编码是否存在。
|
||||
if (userService.getByLoginCode(user) != null){
|
||||
if (UserUtils.getByLoginCode(user.getLoginCode()) != null){
|
||||
return renderResult(Global.FALSE, "登录账号已存在!");
|
||||
}
|
||||
// 生成验证码,并缓存。
|
||||
@@ -271,9 +290,9 @@ public class AccountController extends BaseController{
|
||||
* @param user 用户信息参数
|
||||
* @param validType 验证方式:mobile、email
|
||||
*/
|
||||
@PostMapping(value = "saveRegisterUserByValidCode")
|
||||
@PostMapping(value = "saveRegByValidCode")
|
||||
@ResponseBody
|
||||
public String saveRegisterUserByValidCode(User user, String regValidCode, HttpServletRequest request) {
|
||||
public String saveRegByValidCode(User user, String regValidCode, HttpServletRequest request) {
|
||||
if (!"true".equals(Global.getConfig("sys.account.registerUser"))){
|
||||
return renderResult(Global.FALSE, "当前系统没有开启注册功能!");
|
||||
}
|
||||
@@ -285,6 +304,11 @@ public class AccountController extends BaseController{
|
||||
String mobile = (String)UserUtils.getCache("regMobile");
|
||||
String validCode = (String)UserUtils.getCache("regValidCode");
|
||||
Date date = (Date)UserUtils.getCache("regLastDate");
|
||||
|
||||
// 一同验证保存的用户名和验证码是否正确(如果只校验验证码,不验证用户名,则会有获取验证码后修改用户名的漏洞)
|
||||
if (!(loginCode != null && loginCode.equals(user.getLoginCode()))){
|
||||
return renderResult(Global.FALSE, "非法操作。");
|
||||
}
|
||||
|
||||
// 验证码是否超时
|
||||
boolean isTimeout = true;
|
||||
@@ -292,11 +316,8 @@ public class AccountController extends BaseController{
|
||||
if("0".equals(validTime) || (date != null && (System.currentTimeMillis()-date.getTime())/(1000L) < 60*Long.parseLong(validTime))){
|
||||
isTimeout = false;
|
||||
}
|
||||
|
||||
// 一同验证保存的用户名和验证码是否正确(如果只校验验证码,不验证用户名,则会有获取验证码后修改用户名的漏洞)
|
||||
if (!(loginCode != null && loginCode.equals(user.getLoginCode())
|
||||
&& validCode != null && validCode.equals(regValidCode) && !isTimeout)){
|
||||
return renderResult(Global.FALSE, "验证码不正确或已失效!");
|
||||
if (!(validCode != null && validCode.equals(regValidCode) && !isTimeout)){
|
||||
return renderResult(Global.FALSE, "验证码不正确或已失效,请重新获取验证码!");
|
||||
}
|
||||
|
||||
// 非空数据校验。
|
||||
@@ -333,33 +354,39 @@ public class AccountController extends BaseController{
|
||||
* 发送邮件验证码
|
||||
*/
|
||||
private String sendEmailValidCode(User user, String code, String title){
|
||||
String account = user.getEmail();
|
||||
try {
|
||||
title = user.getUserName() + "(" + user.getLoginCode() + ")"+title+"验证码";
|
||||
String content = "尊敬的用户,您好!\n\n您的验证码是:" + code +"(请勿透露给其他人)\n\n"
|
||||
+ "请复制后,填写在你的验证码窗口完成验证。\n\n本邮件由系统自动发出,请勿回复。\n\n感谢您的使用。";
|
||||
String receiveUserCode = "[CODE]"+user.getEmail();
|
||||
MsgPushUtils.push(MsgPush.TYPE_EMAIL, title, content, null, null, receiveUserCode);
|
||||
+ "请复制后,填写在你的验证码窗口完成验证。\n\n本邮件由系统自动发出,请勿回复。\n\n感谢您的使用!";
|
||||
// String receiveUserCode = "[CODE]"+account;
|
||||
// MsgPushUtils.push(MsgPush.TYPE_EMAIL, title, content, null, null, receiveUserCode);
|
||||
EmailUtils.send(account, title, content);
|
||||
} catch (Exception e) {
|
||||
logger.error(title+"发送邮件错误。", e);
|
||||
return renderResult(Global.FALSE, "系统出现了点问题,错误信息:" + e.getMessage());
|
||||
}
|
||||
return renderResult(Global.TRUE, "邮件已发送,请接收并填写验证码!");
|
||||
account = account.replaceAll("([\\w\\W]?)([\\w\\W]+)([\\w\\W])(@[\\w\\W]+)", "$1****$3$4");
|
||||
return renderResult(Global.TRUE, "验证码已发送到“"+account+"”邮箱账号,请尽快查收!");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 发送短信验证码
|
||||
*/
|
||||
private String sendSmsValidCode(User user, String code, String title){
|
||||
String account = user.getMobile();
|
||||
try {
|
||||
title = user.getUserName() + "(" + user.getLoginCode() + ")"+title+"验证码";
|
||||
String content = "您好,您的验证码是:" + code +"(请勿透露给其他人)感谢您的使用。";
|
||||
String receiveUserCode = "[CODE]"+user.getMobile();
|
||||
MsgPushUtils.push(MsgPush.TYPE_SMS, title, content, null, null, receiveUserCode);
|
||||
// String receiveUserCode = "[CODE]"+account;
|
||||
// MsgPushUtils.push(MsgPush.TYPE_SMS, title, content, null, null, receiveUserCode);
|
||||
SmsUtils.send(content, account);
|
||||
} catch (Exception e) {
|
||||
logger.error(title+"发送短信错误。", e);
|
||||
return renderResult(Global.FALSE, "系统出现了点问题,错误信息:" + e.getMessage());
|
||||
}
|
||||
return renderResult(Global.TRUE, "短信已发送,请接收并填写验证码!");
|
||||
account = account.replaceAll("(\\d{3})(\\d+)(\\d{3})","$1****$3");
|
||||
return renderResult(Global.TRUE, "验证码已发送到“"+account+"”的手机号码,请尽快查收!");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -155,6 +155,13 @@ user:
|
||||
# 多租户模式(SAAS模式)(专业版)
|
||||
useCorpModel: false
|
||||
|
||||
# 自助账号服务
|
||||
account:
|
||||
# 注册用户
|
||||
registerUser:
|
||||
enabled: true
|
||||
userTypes: 0, 1
|
||||
|
||||
# 任务调度(个人版+)
|
||||
job:
|
||||
|
||||
@@ -421,10 +428,10 @@ msg:
|
||||
# 短信网关
|
||||
sms:
|
||||
beanName: smsSendService
|
||||
url: http://localhost:80/msg/sendSms
|
||||
data: account=demo&pswd=demo&product=
|
||||
prefix: ~
|
||||
suffix: 【JeeSite】
|
||||
url: http://lehuo520.cn/a/sms/api
|
||||
data: username=jeesite&password=jeesite.com
|
||||
prefix: 【JeeSite】
|
||||
suffix: ~
|
||||
|
||||
# 微信相关
|
||||
weixin:
|
||||
|
||||
@@ -0,0 +1,187 @@
|
||||
<% layout('/layouts/default.html', {title: '忘记密码', libs: ['validate'], bodyClass: 'login-page'}){ %>
|
||||
<% include('/include/upgrade.html'){} // 如果客户浏览器版本过低,则显示浏览器升级提示。 %>
|
||||
<link rel="stylesheet" href="${ctxStatic}/icheck/1.0/square/blue.css?${_version}">
|
||||
<link rel="stylesheet" href="${ctxStatic}/jquery-toastr/2.0/toastr.min.css?${_version}">
|
||||
<link rel="stylesheet" href="${ctxStatic}/modules/sys/sysLogin.css?${_version}">
|
||||
<% var productName = @Global.getConfig('productName'), productVersion = @Global.getConfig('productVersion'); %>
|
||||
<div class="login-box" style="margin-top:4%">
|
||||
<div class="login-logo" title="${productName}">
|
||||
<a href="${ctxPath}/account/forgetPwd"><b>${productName}</b> <small>${productVersion}</small></a>
|
||||
</div>
|
||||
<div class="login-box-body">
|
||||
<form id="forgetForm" action="${ctxPath}/account/forgetPwd" method="post">
|
||||
<div class="form-group has-feedback">
|
||||
<select id="fp_validType" name="op" class="form-control">
|
||||
<option value="mobile">使用手机号码找回您的密码</option>
|
||||
<option value="email">使用电子邮箱找回您的密码</option>
|
||||
<option value="question">使用保密问题找回您的密码</option>
|
||||
</select>
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function(){
|
||||
$('#fp_validType').change(function(){
|
||||
var val = $(this).val(), action = '';
|
||||
$('.fp-element').addClass('hide').removeClass('block');
|
||||
$('.fp-'+val).addClass('block').removeClass('hide');
|
||||
setTimeout(function(){
|
||||
$('#fp_loginCode').focus();
|
||||
}, 100);
|
||||
if (val == 'mobile' || val == 'email'){
|
||||
var txt = (val == 'mobile' ? '手机' : '邮箱')
|
||||
$('#fpValidCode').attr('placeholder', txt+'验证码')
|
||||
.attr('data-msg-required', '请填写'+txt+'验证码.');
|
||||
$('#sendFpValidCode').val('获取'+txt+'验证码');
|
||||
action = '${ctxPath}/account/savePwdByValidCode';
|
||||
}else if(val == 'question'){
|
||||
action = '${ctxPath}/account/savePwdByPwdQuestion';
|
||||
}
|
||||
$('#forgetForm').attr('action', action);
|
||||
}).change();
|
||||
});
|
||||
</script>
|
||||
</div>
|
||||
<div class="form-group has-feedback">
|
||||
<span class="fa fa-user form-control-feedback"></span>
|
||||
<input type="text" id="fp_loginCode" name="loginCode" class="form-control required" data-msg-required="请填写登录账号." placeholder="登录账号" />
|
||||
</div>
|
||||
<div class="form-group has-feedback fp-element fp-mobile fp-email fp-question">
|
||||
<#form:validcode id="fp_validCode" name="validCode" isRequired="true" isRemote="true" isLazy="false"/>
|
||||
</div>
|
||||
<div class="form-group has-feedback fp-element fp-mobile fp-email">
|
||||
<div class="input-group">
|
||||
<input type="text" id="fpValidCode" name="fpValidCode" class="form-control required"
|
||||
data-msg-required="请填写手机验证码." placeholder="手机验证码" />
|
||||
<span class="input-group-btn">
|
||||
<input type="button" id="sendFpValidCode" value="获取手机验证码" class="btn btn-flat"/>
|
||||
</span>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
var waitTime = 60;
|
||||
function sendTime(o) {
|
||||
if (waitTime == 0) {
|
||||
o.removeAttribute("disabled");
|
||||
o.value = "获取验证码";
|
||||
waitTime = 60;
|
||||
} else {
|
||||
o.setAttribute("disabled", true);
|
||||
o.value = "重新发送(" + waitTime + ")";
|
||||
waitTime--;
|
||||
setTimeout(function() {
|
||||
sendTime(o)
|
||||
}, 1000);
|
||||
}
|
||||
}
|
||||
$('#sendFpValidCode').click(function() {
|
||||
var $this = this;
|
||||
js.ajaxSubmit('${ctxPath}/account/getFpValidCode', {
|
||||
validType: $('#fp_validType').val(),
|
||||
loginCode : $('#fp_loginCode').val(),
|
||||
validCode : $('#fp_validCode').val()
|
||||
}, function(data){
|
||||
js.showMessage(data.message);
|
||||
if (data.result == 'true'){
|
||||
sendTime($this);
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</div>
|
||||
<div class="form-group has-feedback fp-element fp-question clearfix">
|
||||
<input type="button" id="fp_getQuestion" value="获取保密问题" class="btn btn-default btn-block btn-flat"/>
|
||||
<script type="text/javascript">
|
||||
$('#fp_getQuestion').click(function() {
|
||||
js.ajaxSubmit('${ctxPath}/account/getPwdQuestion', {
|
||||
loginCode : $('#fp_loginCode').val(),
|
||||
validCode : $('#fp_validCode').val()
|
||||
}, function(data){
|
||||
js.showMessage(data.message);
|
||||
if (data.result == 'true'){
|
||||
$('#fp_q1').text(data.pwdQuestion);
|
||||
$('#fp_q2').text(data.pwdQuestion2);
|
||||
$('#fp_q3').text(data.pwdQuestion3);
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</div>
|
||||
<div class="form-group has-feedback fp-element fp-question">
|
||||
问题1:<span id="fp_q1"></span>
|
||||
</div>
|
||||
<div class="form-group has-feedback fp-element fp-question">
|
||||
<span class="fa fa-question-circle form-control-feedback"></span>
|
||||
<input type="text" name="pwdQuestionAnswer" class="form-control required"
|
||||
data-msg-required="请填写答案1." placeholder="答案1 " />
|
||||
</div>
|
||||
<div class="form-group has-feedback fp-element fp-question">
|
||||
问题2:<span id="fp_q2"></span>
|
||||
</div>
|
||||
<div class="form-group has-feedback fp-element fp-question">
|
||||
<span class="fa fa-question-circle form-control-feedback"></span>
|
||||
<input type="text" name="pwdQuestionAnswer2" class="form-control required"
|
||||
data-msg-required="请填写答案2." placeholder="答案2" />
|
||||
</div>
|
||||
<div class="form-group has-feedback fp-element fp-question">
|
||||
问题3:<span id="fp_q3"></span>
|
||||
</div>
|
||||
<div class="form-group has-feedback fp-element fp-question">
|
||||
<span class="fa fa-question-circle form-control-feedback"></span>
|
||||
<input type="text" name="pwdQuestionAnswer3" class="form-control required"
|
||||
data-msg-required="请填写答案3." placeholder="答案3" />
|
||||
</div>
|
||||
<div class="form-group has-feedback clearfix">
|
||||
<strong>设置新密码:</strong>
|
||||
</div>
|
||||
<div class="form-group has-feedback">
|
||||
<span class="fa fa-lock form-control-feedback"></span>
|
||||
<input type="password" autocomplete="off" id="fp_password" name="password"
|
||||
class="form-control required" data-msg-required="请填写新密码."
|
||||
rangelength="3,50" data-msg-rangelength="新密码长度不能小于3并大于50个字符."
|
||||
placeholder="新密码" />
|
||||
</div>
|
||||
<div class="form-group has-feedback">
|
||||
<span class="fa fa-lock form-control-feedback"></span>
|
||||
<input type="password" autocomplete="off" id="fp_confirmPassword" name="confirmPassword"
|
||||
class="form-control required" data-msg-required="请填写确认新密码."
|
||||
rangelength="3,50" data-msg-rangelength="新密码长度不能小于3并大于50个字符."
|
||||
equalTo="#fp_password" data-msg-equalTo="新密码与确认新密码不同."
|
||||
placeholder="确认新密码" />
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-6">
|
||||
<button type="submit" class="btn btn-primary btn-block btn-flat"
|
||||
id="btnSubmit">${text('提交')}</button>
|
||||
</div>
|
||||
<div class="col-xs-6">
|
||||
<button type="button" class="btn btn-default btn-block btn-flat"
|
||||
id="btnReset">${text('返回')}</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="login-copyright">
|
||||
© ${@DateUtils.getYear()} ${productName} - Powered By <a href="http://jeesite.com">JeeSite</a>.
|
||||
</div>
|
||||
</div>
|
||||
<% } %>
|
||||
<script>var secretKey = '${@Global.getConfig("shiro.loginSubmit.secretKey")}';</script>
|
||||
<script src="${ctxStatic}/jquery-toastr/2.0/toastr.min.js?${_version}"></script>
|
||||
<script src="${ctxStatic}/common/des.js?${_version}"></script>
|
||||
<script>
|
||||
$('#forgetForm').validate({
|
||||
ignore: ":hidden",
|
||||
submitHandler: function(form) {
|
||||
js.ajaxSubmitForm($(form), function(data){
|
||||
if (data.result == "true"){
|
||||
alert(data.message);
|
||||
location = "${ctx}/login";
|
||||
}else{
|
||||
js.showMessage(data.message);
|
||||
$('#forgetForm').reset();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
$('#btnReset').click(function(){
|
||||
location = '${ctx}/login';
|
||||
});
|
||||
</script>
|
||||
Reference in New Issue
Block a user