ofibz登陆功能有通过电子邮件找会密码的功能,但找回密码功能需要配置一个发送email的邮箱账号和smtp服务器的配置,具体配置如下:
1:在ofbiz数据库的表product_store_email_settings中找到from_address字段,将该字段中值全部修改成配置的默认发送账号
2:在general.properties中配置smtp参数
# -- The default domainname used in the notification emails links
# as 'baseUrl' and 'baseSecureUrl' are set in the url.properties file.
# -- mail notifications enabled (Y|N)
mail.notifications.enabled=Y
# -- redirect all mail notifications to this address for testing
#mail.notifications.redirectTo=
# -- the default mail server to use
mail.smtp.relay.host=smtp.126.com
# -- SMTP Auth settings
mail.smtp.auth.user=XXXXXXXX----------------------(邮箱名称)
mail.smtp.auth.password=XXXXXXXXXXXXXXX------(邮箱密码)
# -- Additional Required Fields needed for Gmail and other non traditional smtp servers
# -- These added fields also work for Yahoo business mail for instance
# -- Gmail smtp port can be either 465 or 587
mail.smtp.port=25
# -- Gmail requires StartTLS
mail.smtp.starttls.enable=true
# -- Gmail requires a JSSE socket factory, the following socketFactory settings will override JavaMail's default socketFactory settings
# -- Port needs to be the same as mail.smtp.port
mail.smtp.socketFactory.port=25
#mail.smtp.socketFactory.class=javax.net.ssl.SSLSocketFactory
#--Fallback [true|false] determines whether you will allow a non secure connection if you are unable to get a secure one
#mail.smtp.socketFactory.fallback=false
3:配置完成后需要重启ofbiz,配置才能生效,再次登录找回密码就能收到一封邮件
4:找回密码的相关代码导读
在controller.xml文件中可以找到找回密码对应的实现:
<request-map uri="forgotpassword"> <security https="true" auth="false"/> <event type="java" path="org.ofbiz.securityext.login.LoginEvents" invoke="forgotPassword"/> <response name="success" type="view" value="login"/> <response name="error" type="view" value="login"/> </request-map>
可以看到具体实现在org.ofbiz.securityext.login.LoginEvents类中的forgotPassword方法实现
打开在LoginEvents中看到具体调用到一下代码
public static String emailPassword(HttpServletRequest request, HttpServletResponse response) { String defaultScreenLocation = "component://securityext/widget/EmailSecurityScreens.xml#PasswordEmail"; Delegator delegator = (Delegator) request.getAttribute("delegator"); LocalDispatcher dispatcher = (LocalDispatcher) request.getAttribute("dispatcher"); String productStoreId = ProductStoreWorker.getProductStoreId(request); String errMsg = null; Map<String, String> subjectData = FastMap.newInstance(); subjectData.put("productStoreId", productStoreId); boolean useEncryption = "true".equals(UtilProperties.getPropertyValue("security.properties", "password.encrypt")); String userLoginId = request.getParameter("USERNAME"); subjectData.put("userLoginId", userLoginId); if ((userLoginId != null) && ("true".equals(UtilProperties.getPropertyValue("security.properties", "username.lowercase")))) { userLoginId = userLoginId.toLowerCase(); } if (!UtilValidate.isNotEmpty(userLoginId)) { // the password was incomplete errMsg = UtilProperties.getMessage(resource, "loginevents.username_was_empty_reenter", UtilHttp.getLocale(request)); request.setAttribute("_ERROR_MESSAGE_", errMsg); return "error"; } GenericValue supposedUserLogin = null; String passwordToSend = null; try { supposedUserLogin = delegator.findOne("UserLogin", false, "userLoginId", userLoginId);if (supposedUserLogin == null) { // the Username was not found errMsg = UtilProperties.getMessage(resource, "loginevents.username_not_found_reenter", UtilHttp.getLocale(request)); request.setAttribute("_ERROR_MESSAGE_", errMsg); return "error"; } if (useEncryption) { // password encrypted, can't send, generate new password and email to user passwordToSend = RandomStringUtils.randomAlphanumeric(Integer.parseInt(UtilProperties.getPropertyValue("security", "password.length.min", "5"))); supposedUserLogin.set("currentPassword", HashCrypt.getDigestHash(passwordToSend, LoginServices.getHashType())); supposedUserLogin.set("passwordHint", "Auto-Generated Password"); if ("true".equals(UtilProperties.getPropertyValue("security.properties", "password.email_password.require_password_change"))){ supposedUserLogin.set("requirePasswordChange", "Y"); } } else { passwordToSend = supposedUserLogin.getString("currentPassword"); } } catch (GenericEntityException e) { Debug.logWarning(e, "", module); Map<String, String> messageMap = UtilMisc.toMap("errorMessage", e.toString()); errMsg = UtilProperties.getMessage(resource, "loginevents.error_accessing_password", messageMap, UtilHttp.getLocale(request)); request.setAttribute("_ERROR_MESSAGE_", errMsg); return "error"; } if (supposedUserLogin == null) { // the Username was not found Map<String, String> messageMap = UtilMisc.toMap("userLoginId", userLoginId); errMsg = UtilProperties.getMessage(resource, "loginevents.user_with_the_username_not_found", messageMap, UtilHttp.getLocale(request)); request.setAttribute("_ERROR_MESSAGE_", errMsg); return "error"; } StringBuilder emails = new StringBuilder(); GenericValue party = null; try { party = supposedUserLogin.getRelatedOne("Party"); } catch (GenericEntityException e) { Debug.logWarning(e, "", module); party = null; } if (party != null) { Iterator<GenericValue> emailIter = UtilMisc.toIterator(ContactHelper.getContactMechByPurpose(party, "PRIMARY_EMAIL", false)); while (emailIter != null && emailIter.hasNext()) { GenericValue email = emailIter.next(); emails.append(emails.length() > 0 ? "," : "").append(email.getString("infoString")); } } if (!UtilValidate.isNotEmpty(emails.toString())) { // the Username was not found errMsg = UtilProperties.getMessage(resource, "loginevents.no_primary_email_address_set_contact_customer_service", UtilHttp.getLocale(request)); request.setAttribute("_ERROR_MESSAGE_", errMsg); return "error"; } //前面主要是从request中获取一些配置参数 // get the ProductStore email settings GenericValue productStoreEmail = null; try { productStoreEmail = delegator.findOne("ProductStoreEmailSetting", false, "productStoreId", productStoreId, "emailType", "PRDS_PWD_RETRIEVE");//从Productstoreemaisetting中获取发送email的账号 } catch (GenericEntityException e) { Debug.logError(e, "Problem getting ProductStoreEmailSetting", module); } if (productStoreEmail == null) { errMsg = UtilProperties.getMessage(resource, "loginevents.problems_with_configuration_contact_customer_service", UtilHttp.getLocale(request)); request.setAttribute("_ERROR_MESSAGE_", errMsg); return "error"; } String bodyScreenLocation = productStoreEmail.getString("bodyScreenLocation"); if (UtilValidate.isEmpty(bodyScreenLocation)) { bodyScreenLocation = defaultScreenLocation; } // set the needed variables in new context Map<String, Object> bodyParameters = FastMap.newInstance(); bodyParameters.put("useEncryption", Boolean.valueOf(useEncryption)); bodyParameters.put("password", UtilFormatOut.checkNull(passwordToSend)); bodyParameters.put("locale", UtilHttp.getLocale(request)); bodyParameters.put("userLogin", supposedUserLogin); bodyParameters.put("productStoreId", productStoreId); Map<String, Object> serviceContext = FastMap.newInstance(); serviceContext.put("bodyScreenUri", bodyScreenLocation); serviceContext.put("bodyParameters", bodyParameters); serviceContext.put("subject", productStoreEmail.getString("subject")); serviceContext.put("sendFrom", productStoreEmail.get("fromAddress")); serviceContext.put("sendCc", productStoreEmail.get("ccAddress")); serviceContext.put("sendBcc", productStoreEmail.get("bccAddress")); serviceContext.put("contentType", productStoreEmail.get("contentType")); serviceContext.put("sendTo", emails.toString()); serviceContext.put("partyId", party.getString("partyId")); try { Map<String, Object> result = dispatcher.runSync("sendMailFromScreen", serviceContext); if (ModelService.RESPOND_ERROR.equals(result.get(ModelService.RESPONSE_MESSAGE))) { Map<String, Object> messageMap = UtilMisc.toMap("errorMessage", result.get(ModelService.ERROR_MESSAGE)); errMsg = UtilProperties.getMessage(resource, "loginevents.error_unable_email_password_contact_customer_service_errorwas", messageMap, UtilHttp.getLocale(request)); request.setAttribute("_ERROR_MESSAGE_", errMsg); return "error"; } } catch (GenericServiceException e) { Debug.logWarning(e, "", module); errMsg = UtilProperties.getMessage(resource, "loginevents.error_unable_email_password_contact_customer_service", UtilHttp.getLocale(request)); request.setAttribute("_ERROR_MESSAGE_", errMsg); return "error"; } // don't save password until after it has been sent if (useEncryption) { try { supposedUserLogin.store(); } catch (GenericEntityException e) { Debug.logWarning(e, "", module); Map<String, String> messageMap = UtilMisc.toMap("errorMessage", e.toString()); errMsg = UtilProperties.getMessage(resource, "loginevents.error_saving_new_password_email_not_correct_password", messageMap, UtilHttp.getLocale(request)); request.setAttribute("_ERROR_MESSAGE_", errMsg); return "error"; } } if (useEncryption) { errMsg = UtilProperties.getMessage(resource, "loginevents.new_password_createdandsent_check_email", UtilHttp.getLocale(request)); request.setAttribute("_EVENT_MESSAGE_", errMsg); } else { errMsg = UtilProperties.getMessage(resource, "loginevents.new_password_sent_check_email", UtilHttp.getLocale(request)); request.setAttribute("_EVENT_MESSAGE_", errMsg); } return "success"; }
email的发送过程在framework\common\src\org\ofbiz\common\email\EmailServices.java中实现
public static Map<String, Object> sendMail(DispatchContext ctx, Map<String, ? extends Object> context) { String communicationEventId = (String) context.get("communicationEventId"); String orderId = (String) context.get("orderId"); Locale locale = (Locale) context.get("locale"); if (communicationEventId != null) { Debug.logInfo("SendMail Running, for communicationEventId : " + communicationEventId, module); } Map<String, Object> results = ServiceUtil.returnSuccess(); String subject = (String) context.get("subject"); subject = FlexibleStringExpander.expandString(subject, context); String partyId = (String) context.get("partyId"); String body = (String) context.get("body"); List<Map<String, Object>> bodyParts = UtilGenerics.checkList(context.get("bodyParts")); GenericValue userLogin = (GenericValue) context.get("userLogin"); results.put("communicationEventId", communicationEventId); results.put("partyId", partyId); results.put("subject", subject); if (UtilValidate.isNotEmpty(orderId)) { results.put("orderId", orderId); } if (UtilValidate.isNotEmpty(body)) { body = FlexibleStringExpander.expandString(body, context); results.put("body", body); } if (UtilValidate.isNotEmpty(bodyParts)) { results.put("bodyParts", bodyParts); } results.put("userLogin", userLogin); String sendTo = (String) context.get("sendTo"); String sendCc = (String) context.get("sendCc"); String sendBcc = (String) context.get("sendBcc"); // check to see if we should redirect all mail for testing String redirectAddress = UtilProperties.getPropertyValue("general.properties", "mail.notifications.redirectTo"); if (UtilValidate.isNotEmpty(redirectAddress)) { String originalRecipients = " [To: " + sendTo + ", Cc: " + sendCc + ", Bcc: " + sendBcc + "]"; subject += originalRecipients; sendTo = redirectAddress; sendCc = null; sendBcc = null; } String sendFrom = (String) context.get("sendFrom"); String sendType = (String) context.get("sendType"); String port = (String) context.get("port"); String socketFactoryClass = (String) context.get("socketFactoryClass"); String socketFactoryPort = (String) context.get("socketFactoryPort"); String socketFactoryFallback = (String) context.get("socketFactoryFallback"); String sendVia = (String) context.get("sendVia"); String authUser = (String) context.get("authUser"); String authPass = (String) context.get("authPass"); String messageId = (String) context.get("messageId"); String contentType = (String) context.get("contentType"); Boolean sendPartial = (Boolean) context.get("sendPartial"); Boolean isStartTLSEnabled = (Boolean) context.get("startTLSEnabled"); boolean useSmtpAuth = false; // define some default if (sendType == null || sendType.equals("mail.smtp.host")) { sendType = "mail.smtp.host"; if (UtilValidate.isEmpty(sendVia)) { sendVia = UtilProperties.getPropertyValue("general.properties", "mail.smtp.relay.host", "localhost"); } if (UtilValidate.isEmpty(authUser)) { authUser = UtilProperties.getPropertyValue("general.properties", "mail.smtp.auth.user"); } if (UtilValidate.isEmpty(authPass)) { authPass = UtilProperties.getPropertyValue("general.properties", "mail.smtp.auth.password"); } if (UtilValidate.isNotEmpty(authUser)) { useSmtpAuth = true; } if (UtilValidate.isEmpty(port)) { port = UtilProperties.getPropertyValue("general.properties", "mail.smtp.port"); } if (UtilValidate.isEmpty(socketFactoryPort)) { socketFactoryPort = UtilProperties.getPropertyValue("general.properties", "mail.smtp.socketFactory.port"); } if (UtilValidate.isEmpty(socketFactoryClass)) { socketFactoryClass = UtilProperties.getPropertyValue("general.properties", "mail.smtp.socketFactory.class"); } if (UtilValidate.isEmpty(socketFactoryFallback)) { socketFactoryFallback = UtilProperties.getPropertyValue("general.properties", "mail.smtp.socketFactory.fallback", "false"); } if (sendPartial == null) { sendPartial = UtilProperties.propertyValueEqualsIgnoreCase("general.properties", "mail.smtp.sendpartial", "true") ? true : false; } if (isStartTLSEnabled == null) { isStartTLSEnabled = UtilProperties.propertyValueEqualsIgnoreCase("general.properties", "mail.smtp.starttls.enable", "true"); } } else if (sendVia == null) { return ServiceUtil.returnError(UtilProperties.getMessage(resource, "CommonEmailSendMissingParameterSendVia", locale)); } if (contentType == null) { contentType = "text/html"; } if (UtilValidate.isNotEmpty(bodyParts)) { contentType = "multipart/mixed"; } results.put("contentType", contentType); Session session; MimeMessage mail; try { Properties props = System.getProperties(); props.put(sendType, sendVia); if (UtilValidate.isNotEmpty(port)) { props.put("mail.smtp.port", port); } if (UtilValidate.isNotEmpty(socketFactoryPort)) { props.put("mail.smtp.socketFactory.port", socketFactoryPort); } if (UtilValidate.isNotEmpty(socketFactoryClass)) { props.put("mail.smtp.socketFactory.class", socketFactoryClass); Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider()); } if (UtilValidate.isNotEmpty(socketFactoryFallback)) { props.put("mail.smtp.socketFactory.fallback", socketFactoryFallback); } if (useSmtpAuth) { props.put("mail.smtp.auth", "true"); } if (sendPartial != null) { props.put("mail.smtp.sendpartial", sendPartial ? "true" : "false"); } if (isStartTLSEnabled) { props.put("mail.smtp.starttls.enable", "true"); } session = Session.getInstance(props); boolean debug = UtilProperties.propertyValueEqualsIgnoreCase("general.properties", "mail.debug.on", "Y"); session.setDebug(debug); mail = new MimeMessage(session); if (messageId != null) { mail.setHeader("In-Reply-To", messageId); mail.setHeader("References", messageId); } mail.setFrom(new InternetAddress(sendFrom)); mail.setSubject(subject, "UTF-8"); mail.setHeader("X-Mailer", "Apache OFBiz, The Apache Open For Business Project"); mail.setSentDate(new Date()); mail.addRecipients(Message.RecipientType.TO, sendTo); if (UtilValidate.isNotEmpty(sendCc)) { mail.addRecipients(Message.RecipientType.CC, sendCc); } if (UtilValidate.isNotEmpty(sendBcc)) { mail.addRecipients(Message.RecipientType.BCC, sendBcc); } if (UtilValidate.isNotEmpty(bodyParts)) { // check for multipart message (with attachments) // BodyParts contain a list of Maps items containing content(String) and type(String) of the attachement MimeMultipart mp = new MimeMultipart(); Debug.logInfo(bodyParts.size() + " multiparts found",module); for (Map<String, Object> bodyPart: bodyParts) { Object bodyPartContent = bodyPart.get("content"); MimeBodyPart mbp = new MimeBodyPart(); if (bodyPartContent instanceof String) { Debug.logInfo("part of type: " + bodyPart.get("type") + " and size: " + bodyPart.get("content").toString().length() , module); mbp.setText((String) bodyPartContent, "UTF-8", ((String) bodyPart.get("type")).substring(5)); } else if (bodyPartContent instanceof byte[]) { ByteArrayDataSource bads = new ByteArrayDataSource((byte[]) bodyPartContent, (String) bodyPart.get("type")); Debug.logInfo("part of type: " + bodyPart.get("type") + " and size: " + ((byte[]) bodyPartContent).length , module); mbp.setDataHandler(new DataHandler(bads)); } else if (bodyPartContent instanceof DataHandler) { mbp.setDataHandler((DataHandler) bodyPartContent); } else { mbp.setDataHandler(new DataHandler(bodyPartContent, (String) bodyPart.get("type"))); } String fileName = (String) bodyPart.get("filename"); if (fileName != null) { mbp.setFileName(fileName); } mp.addBodyPart(mbp); } mail.setContent(mp); mail.saveChanges(); } else { // create the singelpart message if (contentType.startsWith("text")) { mail.setText(body, "UTF-8", contentType.substring(5)); } else { mail.setContent(body, contentType); } mail.saveChanges(); } } catch (MessagingException e) { Debug.logError(e, "MessagingException when creating message to [" + sendTo + "] from [" + sendFrom + "] cc [" + sendCc + "] bcc [" + sendBcc + "] subject [" + subject + "]", module); Debug.logError("Email message that could not be created to [" + sendTo + "] had context: " + context, module); return ServiceUtil.returnError(UtilProperties.getMessage(resource, "CommonEmailSendMessagingException", UtilMisc.toMap("sendTo", sendTo, "sendFrom", sendFrom, "sendCc", sendCc, "sendBcc", sendBcc, "subject", subject), locale)); } catch (IOException e) { Debug.logError(e, "IOExcepton when creating message to [" + sendTo + "] from [" + sendFrom + "] cc [" + sendCc + "] bcc [" + sendBcc + "] subject [" + subject + "]", module); Debug.logError("Email message that could not be created to [" + sendTo + "] had context: " + context, module); return ServiceUtil.returnError(UtilProperties.getMessage(resource, "CommonEmailSendIOException", UtilMisc.toMap("sendTo", sendTo, "sendFrom", sendFrom, "sendCc", sendCc, "sendBcc", sendBcc, "subject", subject), locale)); } // check to see if sending mail is enabled String mailEnabled = UtilProperties.getPropertyValue("general.properties", "mail.notifications.enabled", "N"); if (!"Y".equalsIgnoreCase(mailEnabled)) { // no error; just return as if we already processed Debug.logImportant("Mail notifications disabled in general.properties; mail with subject [" + subject + "] not sent to addressee [" + sendTo + "]", module); Debug.logVerbose("What would have been sent, the addressee: " + sendTo + " subject: " + subject + " context: " + context, module); results.put("messageWrapper", new MimeMessageWrapper(session, mail)); return results; } Transport trans = null; try { trans = session.getTransport("smtp"); if (!useSmtpAuth) { trans.connect(); } else { trans.connect(sendVia, authUser, authPass); } trans.sendMessage(mail, mail.getAllRecipients()); results.put("messageWrapper", new MimeMessageWrapper(session, mail)); results.put("messageId", mail.getMessageID()); trans.close(); } catch (SendFailedException e) { // message code prefix may be used by calling services to determine the cause of the failure Debug.logError(e, "[ADDRERR] Address error when sending message to [" + sendTo + "] from [" + sendFrom + "] cc [" + sendCc + "] bcc [" + sendBcc + "] subject [" + subject + "]", module); List<SMTPAddressFailedException> failedAddresses = FastList.newInstance(); Exception nestedException = null; while ((nestedException = e.getNextException()) != null && nestedException instanceof MessagingException) { if (nestedException instanceof SMTPAddressFailedException) { SMTPAddressFailedException safe = (SMTPAddressFailedException) nestedException; Debug.logError("Failed to send message to [" + safe.getAddress() + "], return code [" + safe.getReturnCode() + "], return message [" + safe.getMessage() + "]", module); failedAddresses.add(safe); break; } } Boolean sendFailureNotification = (Boolean) context.get("sendFailureNotification"); if (sendFailureNotification == null || sendFailureNotification) { sendFailureNotification(ctx, context, mail, failedAddresses); results.put("messageWrapper", new MimeMessageWrapper(session, mail)); try { results.put("messageId", mail.getMessageID()); trans.close(); } catch (MessagingException e1) { Debug.logError(e1, module); } } else { return ServiceUtil.returnError(UtilProperties.getMessage(resource, "CommonEmailSendAddressError", UtilMisc.toMap("sendTo", sendTo, "sendFrom", sendFrom, "sendCc", sendCc, "sendBcc", sendBcc, "subject", subject), locale)); } } catch (MessagingException e) { // message code prefix may be used by calling services to determine the cause of the failure Debug.logError(e, "[CON] Connection error when sending message to [" + sendTo + "] from [" + sendFrom + "] cc [" + sendCc + "] bcc [" + sendBcc + "] subject [" + subject + "]", module); Debug.logError("Email message that could not be sent to [" + sendTo + "] had context: " + context, module); return ServiceUtil.returnError(UtilProperties.getMessage(resource, "CommonEmailSendConnectionError", UtilMisc.toMap("sendTo", sendTo, "sendFrom", sendFrom, "sendCc", sendCc, "sendBcc", sendBcc, "subject", subject), locale)); } return results; }
从代码中可以看出发送的大部分配置都是从context中取出,但smtp的配置是从general.properties文件中获取