Liferay 创建新用户页面中随机文本验证分析

简介:

 Liferay 6.1的创建新用户页面如图:

这个页面的代码在/html/portlet/login/create_account.jsp中: 


  
  
  1. ... 
  2. <portlet:actionURL var="createAccoutURL"> 
  3.     <portlet:param name="saveLastPath" value="0" /> 
  4.     <portlet:param name="struts_action" value="/login/create_account" /> 
  5. </portlet:actionURL> 
  6.  
  7. <aui:form action="<%= createAccoutURL %>" method="post" name="fm"> 
  8.     <aui:input name="<%= Constants.CMD %>" type="hidden" value="<%= Constants.ADD %>" /> 
  9.     <aui:input name="redirect" type="hidden" value="<%= redirect %>" /> 
  10.     <aui:input name="openId" type="hidden" value="<%= openId %>" /> 
  11.  
  12. .. 
  13.  
  14.         <
  15.         UserPasswordException upe = (UserPasswordException)errorException; 
  16.         %> 
  17.  
  18.         <c:if test="<%= upe.getType() == UserPasswordException.PASSWORD_CONTAINS_TRIVIAL_WORDS %>"> 
  19.             <liferay-ui:message key="that-password-uses-common-words-please-enter-in-a-password-that-is-harder-to-guess-i-e-contains-a-mix-of-numbers-and-letters" /> 
  20.         </c:if> 
  21.  
  22.         <c:if test="<%= upe.getType() == UserPasswordException.PASSWORD_INVALID %>"> 
  23.             <liferay-ui:message key="that-password-is-invalid-please-enter-in-a-different-password" /> 
  24.         </c:if> 
  25.  
  26.         <c:if test="<%= upe.getType() == UserPasswordException.PASSWORD_LENGTH %>"> 
  27.             <%= LanguageUtil.format(pageContext, "that-password-is-too-short-or-too-long-please-make-sure-your-password-is-between-x-and-512-characters", String.valueOf(passwordPolicy.getMinLength()), false) %> 
  28.         </c:if> 
  29.  
  30.         <c:if test="<%= upe.getType() == UserPasswordException.PASSWORD_TOO_TRIVIAL %>"> 
  31.             <liferay-ui:message key="that-password-is-too-trivial" /> 
  32.         </c:if> 
  33.  
  34.         <c:if test="<%= upe.getType() == UserPasswordException.PASSWORDS_DO_NOT_MATCH %>"> 
  35.             <liferay-ui:message key="the-passwords-you-entered-do-not-match-each-other-please-re-enter-your-password" /> 
  36.         </c:if> 
  37.     </liferay-ui:error> 
  38.  
  39.     <liferay-ui:error exception="<%= UserScreenNameException.class %>" message="please-enter-a-valid-screen-name" /> 
  40.     <liferay-ui:error exception="<%= WebsiteURLException.class %>" message="please-enter-a-valid-url" /> 
  41.  
  42.     <c:if test='<%= SessionMessages.contains(request, "missingOpenIdUserInformation") %>'> 
  43.         <div class="portlet-msg-info"> 
  44.             <liferay-ui:message key="you-have-successfully-authenticated-please-provide-the-following-required-information-to-access-the-portal" /> 
  45.         </div> 
  46.     </c:if> 
  47.  
  48.     <aui:model-context model="<%= Contact.class %>" /> 
  49.  
  50.     <aui:fieldset> 
  51.         <aui:column> 
  52.             <aui:input model="<%= User.class %>" name="firstName" /> 
  53.  
  54.             <aui:input model="<%= User.class %>" name="middleName" /> 
  55.  
  56.             <aui:input model="<%= User.class %>" name="lastName"> 
  57.                 <c:if test="<%= PrefsPropsUtil.getBoolean(company.getCompanyId(), PropsKeys.USERS_LAST_NAME_REQUIRED, PropsValues.USERS_LAST_NAME_REQUIRED) %>"> 
  58.                     <aui:validator name="required" /> 
  59.                 </c:if> 
  60.             </aui:input> 
  61.  
  62.             <c:if test="<%= !PrefsPropsUtil.getBoolean(company.getCompanyId(), PropsKeys.USERS_SCREEN_NAME_ALWAYS_AUTOGENERATE) %>"> 
  63.                 <aui:input model="<%= User.class %>" name="screenName" /> 
  64.             </c:if> 
  65.  
  66.             <aui:input model="<%= User.class %>" name="emailAddress"> 
  67.                 <c:if test="<%= PrefsPropsUtil.getBoolean(company.getCompanyId(), PropsKeys.USERS_EMAIL_ADDRESS_REQUIRED, PropsValues.USERS_EMAIL_ADDRESS_REQUIRED) %>"> 
  68.                     <aui:validator name="required" /> 
  69.                 </c:if> 
  70.             </aui:input> 
  71.         </aui:column> 
  72.  
  73.         <aui:column> 
  74.             <c:if test="<%= PropsValues.LOGIN_CREATE_ACCOUNT_ALLOW_CUSTOM_PASSWORD %>"> 
  75.                 <aui:input label="password" name="password1" size="30" type="password" value="" /> 
  76.  
  77.                 <aui:input label="enter-again" name="password2" size="30" type="password" value=""> 
  78.                     <aui:validator name="equalTo"> 
  79.                         '#<portlet:namespace />password1' 
  80.                     </aui:validator> 
  81.                 </aui:input> 
  82.             </c:if> 
  83.  
  84.             <c:choose> 
  85.                 <c:when test="<%= PrefsPropsUtil.getBoolean(company.getCompanyId(), PropsKeys.FIELD_ENABLE_COM_LIFERAY_PORTAL_MODEL_CONTACT_BIRTHDAY) %>"> 
  86.                     <aui:input name="birthday" value="<%= birthday %>" /> 
  87.                 </c:when> 
  88.                 <c:otherwise> 
  89.                     <aui:input name="birthdayMonth" type="hidden" value="<%= Calendar.JANUARY %>" /> 
  90.                     <aui:input name="birthdayDay" type="hidden" value="1" /> 
  91.                     <aui:input name="birthdayYear" type="hidden" value="1970" /> 
  92.                 </c:otherwise> 
  93.             </c:choose> 
  94.  
  95.             <c:if test="<%= PrefsPropsUtil.getBoolean(company.getCompanyId(), PropsKeys.FIELD_ENABLE_COM_LIFERAY_PORTAL_MODEL_CONTACT_MALE) %>"> 
  96.                 <aui:select label="gender" name="male"> 
  97.                     <aui:option label="male" value="1" /> 
  98.                     <aui:option label="female" selected="<%= !male %>" value="0" /> 
  99.                 </aui:select> 
  100.             </c:if> 
  101.  
  102.             <c:if test="<%= PropsValues.CAPTCHA_CHECK_PORTAL_CREATE_ACCOUNT %>"> 
  103.                 <portlet:actionURL windowState="<%= LiferayWindowState.EXCLUSIVE.toString() %>" var="captchaURL"> 
  104.                     <portlet:param name="struts_action" value="/login/captcha" /> 
  105.                 </portlet:actionURL> 
  106.  
  107.                 <liferay-ui:captcha url="<%= captchaURL %>" /> 
  108.             </c:if> 
  109.         </aui:column> 
  110.     </aui:fieldset> 
  111.  
  112.     <aui:button-row> 
  113.         <aui:button type="submit" /> 
  114.     </aui:button-row> 
  115. </aui:form> 
  116.  
  117. <liferay-util:include page="/html/portlet/login/navigation.jsp" /> 
  118.  
  119. <c:if test="<%= windowState.equals(WindowState.MAXIMIZED) %>"> 
  120.     <aui:script> 
  121.         Liferay.Util.focusFormField(document.<portlet:namespace />fm.<portlet:namespace />firstName); 
  122.     </aui:script> 
  123. </c:if> 

 

这里我们讲一个比较有趣的地方-随机文本验证:

 

随机文本验证:

这个对应的页面元素为:


  
  
  1. <c:if test="<%= PropsValues.CAPTCHA_CHECK_PORTAL_CREATE_ACCOUNT %>"> 
  2.                 <portlet:actionURL windowState="<%= LiferayWindowState.EXCLUSIVE.toString() %>" var="captchaURL"> 
  3.                     <portlet:param name="struts_action" value="/login/captcha" /> 
  4.                 </portlet:actionURL> 
  5.  
  6.                 <liferay-ui:captcha url="<%= captchaURL %>" /> 
  7.             </c:if> 

 

它的外观部分展示在liferay-ui.tld中:


  
  
  1. <tag> 
  2.         <name>captcha</name> 
  3.         <tag-class>com.liferay.taglib.ui.CaptchaTag</tag-class> 
  4.         <body-content>JSP</body-content> 
  5.         <attribute> 
  6.             <name>url</name> 
  7.             <required>true</required> 
  8.             <rtexprvalue>true</rtexprvalue> 
  9.         </attribute> 
  10.  </tag> 

看出,它的<body-content>是一段jsp代码段:

它只需要一个参数,是从上面的<portlet:param name="struts_action" value="/login/captcha" /> 传过来的。

 

而对应的是tag的类是 CaptchaTag,查看这个类


  
  
  1. ... 
  2.     private static final String _PAGE = "/html/taglib/ui/captcha/page.jsp"
  3. .. 

 

可以知道captcha标记包含的jsp代码位于/html/taglib/ui/captcha/page.jsp中:


  
  
  1. <%@ include file="/html/taglib/ui/captcha/init.jsp" %> 
  2.  
  3. <liferay-util:include page="<%= CaptchaUtil.getTaglibPath() %>" /> 

 

最终找到的页面是/html/taglib/ui/captcha/simplecaptcha.jsp


  
  
  1. ...
  2.  
  3. <%@ include file="/html/taglib/ui/captcha/init.jsp" %> 
  4.  
  5. <
  6. String url = (String)request.getAttribute("liferay-ui:captcha:url"); 
  7.  
  8. boolean captchaEnabled = false
  9.  
  10. try { 
  11.     if (portletRequest != null) { 
  12.         captchaEnabled = CaptchaUtil.isEnabled(portletRequest); 
  13.     } 
  14.     else { 
  15.         captchaEnabled = CaptchaUtil.isEnabled(request); 
  16.     } 
  17. catch (CaptchaMaxChallengesException cmce) { 
  18.     captchaEnabled = true
  19. %> 
  20.  
  21. <c:if test="<%= captchaEnabled %>"> 
  22.     <div class="taglib-captcha"> 
  23.         <img alt="<liferay-ui:message key="text-to-identify" />class="captcha" src="<%= url %>" /> 
  24.  
  25.         <aui:input label="text-verification" name="captchaText" size="10" type="text" value=""> 
  26.             <aui:validator name="required" /> 
  27.         </aui:input> 
  28.     </div> 
  29. </c:if> 

 

对比页面源码,果然这两段是一致的:

 

再深入下去,还能找到更多有趣的发现,比如这个url,是在liferay-ui;captcha:url中指定的:


  
  
  1. String url = (String)request.getAttribute("liferay-ui:captcha:url"); 

 

这个url可以回溯到create_account.jsp中的定义:


  
  
  1. <portlet:actionURL windowState="<%= LiferayWindowState.EXCLUSIVE.toString() %>" var="captchaURL"> 
  2.                 <portlet:param name="struts_action" value="/login/captcha" /> 
  3.             </portlet:actionURL> 
  4.  
  5.             <liferay-ui:captcha url="<%= captchaURL %>" /> 

 

所以这个url不是页面url,而是局部url,这个url指向了随即生成的数字图片地址。

它会提交给struts框架,我们在struts-config.xml中找到与/login/captcha url映射匹配的处理类:


  
  
  1. <action path="/login/captcha" type="com.liferay.portal.captcha.CaptchaPortletAction" /> 

 

我们找到这个类研究下,发现:


  
  
  1. public class CaptchaPortletAction extends PortletAction { 
  2.  
  3.     @Override 
  4.     public void processAction( 
  5.             ActionMapping mapping, ActionForm form, PortletConfig portletConfig, 
  6.             ActionRequest actionRequest, ActionResponse actionResponse) 
  7.         throws Exception { 
  8.  
  9.         try { 
  10.             CaptchaUtil.serveImage(actionRequest, actionResponse); 
  11.  
  12.             setForward(actionRequest, ActionConstants.COMMON_NULL); 
  13.         } 
  14.         catch (Exception e) { 
  15.             _log.error(e); 
  16.         } 
  17.     } 
  18.  
  19. .. 

它最终会让CaptchaUtil来负责绘制图形:


  
  
  1. public static void serveImage( 
  2.             PortletRequest portletRequest, PortletResponse portletResponse) 
  3.         throws IOException { 
  4.  
  5.         getCaptcha().serveImage(portletRequest, portletResponse); 
  6.     } 

而CaptchaUtil最终又会让Captcha类(最终是SimpleCaptchaImpl类)来绘制图形:


  
  
  1. public void serveImage( 
  2.             PortletRequest portletRequest, PortletResponse portletResponse) 
  3.         throws IOException { 
  4.  
  5.         PortletSession portletSession = portletRequest.getPortletSession(); 
  6.  
  7.         nl.captcha.Captcha simpleCaptcha = getSimpleCaptcha(); 
  8.  
  9.         portletSession.setAttribute( 
  10.             WebKeys.CAPTCHA_TEXT, simpleCaptcha.getAnswer()); 
  11.  
  12.         HttpServletResponse response = PortalUtil.getHttpServletResponse( 
  13.             portletResponse); 
  14.  
  15.         CaptchaServletUtil.writeImage( 
  16.             response.getOutputStream(), simpleCaptcha.getImage()); 
  17.     } 

而绘制图形的实际代码在CaptchaServletUtil中,它位于simplecaptcha.jar包中:


  
  
  1. public static void writeImage(HttpServletResponse httpservletresponse, BufferedImage bufferedimage) 
  2.    { 
  3.        httpservletresponse.setHeader("Cache-Control""private,no-cache,no-store"); 
  4.        httpservletresponse.setContentType("image/png"); 
  5.        try 
  6.        { 
  7.            writeImage(((OutputStream) (httpservletresponse.getOutputStream())), bufferedimage); 
  8.        } 
  9.        catch(IOException ioexception) 
  10.        { 
  11.            ioexception.printStackTrace(); 
  12.        } 
  13.    } 

可以看出,这个图片格式为 image/png,并且这个图片永远是不会被浏览器缓存的。

 

最终实际承担画图任务的是ImageIO类:


  
  
  1. ImageIO.write(bufferedimage, "png", outputstream); 




本文转自 charles_wang888 51CTO博客,原文链接:http://blog.51cto.com/supercharles888/900654,如需转载请自行联系原作者

目录
相关文章
|
监控 JavaScript 前端开发
JavaScript与HTML关系及其嵌入方式:新手常犯错误与规避策略
【4月更文挑战第1天】本文介绍了JavaScript与HTML的关系,强调了理解它们的分工和协作对于初学者的重要性。文中列举了新手在嵌入JavaScript时常见的错误,如嵌入位置不当、异步与延迟属性混淆、内联脚本与HTML混杂、忽略浏览器兼容性以及缺乏错误处理。提供了避免这些错误的策略,包括合理安排script标签、使用事件监听器、关注浏览器兼容性、学习调试技巧,并提倡遵循“结构-样式-行为”分离原则和使用错误处理机制。遵循这些最佳实践,有助于提高代码质量和开发效率。
413 1
|
Web App开发 编解码 监控
防御性设计和开发
“防御性编程(Defensive programming)是防御式设计的一种具体体现,它是为了保证,对程序的不可预见的使用,不会造成程序功能上的损坏。它可以被看作是为了减少或消除墨菲定律效力的想法。”
1217 0
防御性设计和开发
|
1月前
|
存储 缓存 数据处理
71_数据版本控制:Git与DVC在LLM开发中的最佳实践
在2025年的大模型(LLM)开发实践中,数据和模型的版本控制已成为确保项目可重复性和团队协作效率的关键环节。与传统软件开发不同,LLM项目面临着独特的数据版本控制挑战:
|
2月前
|
安全 Linux 网络安全
Metasploit Framework 6.4.88 (macOS, Linux, Windows) - 开源渗透测试框架
Metasploit Framework 6.4.88 (macOS, Linux, Windows) - 开源渗透测试框架
544 0
|
5月前
|
Ubuntu API
在Ubuntu上利用SANE API实现跨平台扫描功能的指南
跨平台扫描功能的实现,在Ubuntu上表演起来,只需要SANE这个神奇魔杖,加上一系列施法步骤,每个命令都像是进行咒语施法,只需轻松点击按键,即可驱动扫描仪进行各种跃动。别忘了,这只是开始,在扫描的舞台上,还有许多舞步等待你去开发和探索。
219 14
|
5月前
|
NoSQL MongoDB 开发者
Python与MongoDB的亲密接触:从入门到实战的代码指南
本文详细介绍了Python与MongoDB结合使用的实战技巧,涵盖环境搭建、连接管理、CRUD操作、高级查询、索引优化、事务处理及性能调优等内容。通过15个代码片段,从基础到进阶逐步解析,帮助开发者掌握这对黄金组合的核心技能。内容包括文档结构设计、批量操作优化、聚合管道应用等实用场景,适合希望高效处理非结构化数据的开发者学习参考。
307 0
|
8月前
|
SQL 人工智能 BI
《解锁AI与SQL Server的高效协作,提升并发查询能力》
在数字化转型中,企业业务激增使SQL Server面临并发查询的严峻挑战。传统优化手段难以应对复杂场景,而AI技术通过深度数据分析、智能执行计划调整和动态资源分配,精准解决性能瓶颈。案例表明,AI可大幅提升系统响应速度与吞吐量,助力企业在高并发场景下实现高效稳定运行,为未来业务增长提供坚实保障。
194 5
|
数据可视化 数据管理 大数据
【开源项目】轻量元数据管理解决方案——Marquez
【开源项目】轻量元数据管理解决方案——Marquez
820 57
|
10月前
|
JSON 数据挖掘 开发者
1688 商品评论接口系列(1688API)
1688商品评论接口助力电商数据分析与优化。通过该接口,开发者可获取指定商品的评论数据(如昵称、内容、评分等),支持情感分析和质量反馈收集。接口采用HTTP GET/POST请求,返回JSON格式数据。Python示例代码展示如何调用接口并处理响应。应用场景包括商家产品优化、客户服务提升、市场调研及电商平台数据分析。
380 7
|
10月前
|
人工智能 自然语言处理 数据挖掘
《深度解析:VAEs如何重塑数据生成与重建格局》
变分自编码器(VAEs)是人工智能领域中强大的生成模型,广泛应用于图像生成、语音合成及医疗数据分析。其核心由编码器和解码器组成,通过将数据映射到低维潜在空间并重建,实现高效的数据生成与重建。VAEs的潜在空间具有连续性,并引入概率分布以支持创新生成。损失函数引导编码与解码优化,确保高质量的重建效果。VAEs在图像、医疗和自然语言处理等领域展现出巨大潜力,为各行业带来新的发展机遇。
308 18