本文接着 开发基于JBoss AS 7.2.0的Java EE程序 - 05.如何配置安全域以及使用JAAS进行身份认证和权限控制 - part.1 描述。
4. 用户注册
4.1 war/UserRegisterMBean.java
@ManagedBean
@RequestScoped
public class UserRegisterMBean {
static final Logger logger = Logger.getLogger(UserRegisterMBean.class.getName());
@EJB
private IUserSession userSession;
@EJB
private ISensitiveNameSession sensitiveNameSession;
private String username;//登录名
private String password;//加了Transient注解:仅仅供用户从客户端传递到服务器端以便新增或者修改时使用。
private String passwordRepeat;
private String firstname = "";//真实姓
private String lastname = "";//真实名
private String mobilePhone = "";//手机
private String email ="";//电子邮件。
private String birthday = null;//生日
private Gender gender = Gender.UNKNOWN;//性别
//private String imageLink = "unknown.jpg";//头像链接
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
...//other getters/setters
public String create(){
//检测必须输入属性的合法性*********************************
...
//构造持久化对象*********************************
User user = new User();
//a:必须输入的数据
user.setUsername(this.getUsername().trim());
user.setHashedPassword(HashUtil.createPasswordHash(this.getUsername().trim(), this.getPassword().trim()));
user.setEmail(this.getEmail().trim());
//b:可选输入的数据
if(this.getBirthday()!=null&&this.getBirthday().trim().length()> 0){
user.setBirthday(DateHelper.stringToUtilDate(this.getBirthday().trim()));
}
user.setFirstname(this.getFirstname());
user.setLastname(this.getLastname());
user.setMobilePhone(this.getMobilePhone());
user.setGender(this.getGender());
//持久化对象*********************************
try{
userSession.registerUser(user);
}catch(Exception e){
String errMsg = "错误:"+e.getMessage();
JSFHelper.addErrorMessage(errMsg);
logger.severe(errMsg);
return Constants.RETURN_FAILURE;
}
return Constants.RETURN_SUCCESS;
}
}
4.2 war/register.xhtml
<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
template="/template/template.xhtml">
<ui:define name="title">
<h:outputText value="#{messages['ybxiang.javaarm.register']}" />
</ui:define>
<ui:define name="headMetaData">
</ui:define>
<ui:define name="body">
<h:form id="form" >
<h3><h:outputText value="#{messages['ybxiang.javaarm.register']}"/></h3>
<h:panelGrid columns="2">
<h:outputLabel style="color:red" value="#{messages['ybxiang.javaarm.username']}(*)" for="username" />
<h:inputText id="username" value="#{userRegisterMBean.username}" maxlength="#{entitiesConstantsMBean.maxUsernameLength}" size="90" >
<f:validateLength minimum="#{entitiesConstantsMBean.minUsernameLength}" maximum="#{entitiesConstantsMBean.maxUsernameLength}" />
</h:inputText>
<h:outputText value=""/>
<h:message for="username" styleClass="message" errorClass="errormsg" infoClass="infomsg" warnClass="warnmsg"/>
<h:outputLabel style="color:red" value="#{messages['ybxiang.javaarm.password']}(*)" for="password" />
<h:inputSecret id="password" value="#{userRegisterMBean.password}" maxlength="#{entitiesConstantsMBean.maxPasswordLength}" size="90" >
<f:validateLength minimum="#{entitiesConstantsMBean.minPasswordLength}" maximum="#{entitiesConstantsMBean.maxPasswordLength}" />
</h:inputSecret>
<h:outputText value=""/>
<h:message for="password" styleClass="message" errorClass="errormsg" infoClass="infomsg" warnClass="warnmsg"/>
<h:outputLabel style="color:red" value="#{messages['ybxiang.javaarm.passwordRepeat']}(*)" for="passwordRepeat" />
<h:inputSecret id="passwordRepeat" value="#{userRegisterMBean.passwordRepeat}" maxlength="#{entitiesConstantsMBean.maxPasswordLength}" size="90" >
<f:validateLength minimum="#{entitiesConstantsMBean.minPasswordLength}" maximum="#{entitiesConstantsMBean.maxPasswordLength}" />
</h:inputSecret>
<h:outputText value=""/>
<h:message for="passwordRepeat" styleClass="message" errorClass="errormsg" infoClass="infomsg" warnClass="warnmsg"/>
...
<h:outputText value="."/>
<h:commandButton id="submitButton" value="#{messages['ybxiang.javaarm.register']}" action="#{userRegisterMBean.create()}" />
</h:panelGrid>
</h:form>
</ui:define>
</ui:composition>
4.3 HashUtil.java
请参考:链接 一文。
public class HashUtil {
public static final void testSystemPropertyInEJB(){
System.out.println("SYSTEM_PROPERTY_KEY_JAAS_hashAlgorithm: "+System.getProperty(ServerConstants.SYSTEM_PROPERTY_KEY_JAAS_hashAlgorithm));
}
public static final String getHashAlgorithmFromSystemProperty(){
return System.getProperty(ServerConstants.SYSTEM_PROPERTY_KEY_JAAS_hashAlgorithm, ServerConstants.DEFAULT_JAAS_hashAlgorithm);
}
public static final String getHashEncodingFromSystemProperty(){
return System.getProperty(ServerConstants.SYSTEM_PROPERTY_KEY_JAAS_hashEncoding, ServerConstants.DEFAULT_JAAS_hashEncoding);
}
public static final String getHashCharsetFromSystemProperty(){
return System.getProperty(ServerConstants.SYSTEM_PROPERTY_KEY_JAAS_hashCharset, ServerConstants.DEFAULT_JAAS_hashCharset);
}
public static String createPasswordHash(String username, String password){
return createPasswordHash(
getHashAlgorithmFromSystemProperty(),
getHashEncodingFromSystemProperty(),
getHashCharsetFromSystemProperty(),
username,
password
);
}
public static String createPasswordHash(String hashAlgorithm, String hashEncoding,
String hashCharset, String username, String password){
//method.1
String result = org.jboss.security.auth.spi.Util.createPasswordHash(hashAlgorithm, hashEncoding, hashCharset, username, password);
//method.2: from http://www.ajka-andrej.com/2011/05/22/jboss-6-client-authentication-sd/
//String result2 = CryptoUtil.createPasswordHash(hashAlgorithm, hashEncoding, hashCharset, username, password);
return result;
}
}
4.4 ejb/IUserSession.java
public interface IUserSession {
public void registerUser(User user);
...
}
4.5 ejb/UserSession.java
@Stateless
@Local(IUserSession.class)
public class UserSession implements IUserSession{
@PersistenceContext()
private EntityManager em;
@EJB
ICacheService cacheService;
@EJB
IEmailService emailService;
@EJB
IJaasCacheSession jaasCacheSession;
...
@PermitAll()
public void registerUser(User user){
if(isUsernameExist(user.getUsername())){//已经有唯一性限制了
throw new RuntimeException("该用户名已经备注册(This username already exists)。");
}
if(user.getEmail()==null){
throw new RuntimeException("非法电子邮件地址(Invalid email address)。");
}
if(isEmailOverRegistered(user.getEmail())){
throw new RuntimeException("一个电子邮件地址最多只能注册3个账号(One Email can register at most 3 accounts).");
}
//
user.setActivated(false);//改成false,防止JSF MBean那里错误设置为true。测试的时候,我们用“true”,让用户直接处于激活状态。
em.persist(user);
ActivateCode activateCode = new ActivateCode();
activateCode.setUser(user);
activateCode.setCode(RandomHelper.getRandomString(ActivateCode.CODE_LENGTH));
activateCode.setUsageType(ActivateCode.Usage.USER_ACTIVATE_ACCOUNT.id);
em.persist(activateCode);
//************************************UPDATE user cache!!!
cacheService.updateUserCache_ONLY_by_UserSessionOrLocalEJB(user);
//************************************Send activating code to user's email.
Email email = new Email();
email.setTitle(EmailConstants.USER_REGISTER_ACTIVATION_EMAIL_TITLE);
email.setContent(EmailConstants.getUserRegisterActivatioinEmailContent(user.getUsername(), activateCode.getActivatingLink()));
email.setToUser(user);
em.persist(email);
emailService.sendMail(email);
}
...
}
5. JAAS身份认证 - 用户登陆
5.1 web.xml
我们需要首先在web.xml中配置security-constraint,如果GUEST访问了需要登陆才能访问的链接,那么他将被重定向到登陆页面:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
...
<!-- FORM <auth-method>
refer to: http://www.avajava.com/tutorials/lessons/how-do-i-log-out-of-an-application-that-uses-form-authentication.html -->
<!-- 1. Public Resources -->
<security-constraint>
<web-resource-collection>
<web-resource-name>Public resources - Logged in User</web-resource-name>
<description>Public resources - Logged in User</description>
<url-pattern>/faces/createtopic.xhtml</url-pattern>
<url-pattern>/faces/updatetopic.xhtml</url-pattern>
<url-pattern>/faces/updatepost.xhtml</url-pattern>
<url-pattern>/faces/message.xhtml</url-pattern>
<url-pattern>/faces/search.xhtml</url-pattern>
<url-pattern>/faces/message-action.xhtml</url-pattern>
<url-pattern>/faces/send-message.xhtml</url-pattern>
<url-pattern>/faces/upload.jsp</url-pattern>
<url-pattern>/logoutServlet</url-pattern>
<url-pattern>/upload.xhtml</url-pattern>
<url-pattern>/uploadServlet</url-pattern>
<url-pattern>/UploadServlet</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>*</role-name>
</auth-constraint>
<user-data-constraint>
<transport-guarantee>NONE</transport-guarantee>
</user-data-constraint>
</security-constraint>
<security-constraint>
<web-resource-collection>
<web-resource-name>Public resources - guest</web-resource-name>
<description>Public resources - guest</description>
<url-pattern>/faces/activate.xhtml</url-pattern>
<url-pattern>/faces/activate-success.xhtml</url-pattern>
<url-pattern>/faces/display.xhtml</url-pattern>
<url-pattern>/faces/index.xhtml</url-pattern>
<url-pattern>/faces/index-forum.xhtml</url-pattern>
<url-pattern>/faces/list.xhtml</url-pattern>
<url-pattern>/faces/register-success.xhtml</url-pattern>
</web-resource-collection>
<user-data-constraint>
<transport-guarantee>NONE</transport-guarantee>
</user-data-constraint>
</security-constraint>
<!-- 2. CONFIDENTIAL resources -->
<security-constraint>
<web-resource-collection>
<web-resource-name>CONFIDENTIAL resources - logged in user</web-resource-name>
<description>CONFIDENTIAL resources - logged in user</description>
<url-pattern>/faces/login-https.xhtml</url-pattern>
<url-pattern>/faces/console/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>*</role-name>
</auth-constraint>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
<security-constraint>
<web-resource-collection>
<web-resource-name>CONFIDENTIAL resources - logged in Administrator</web-resource-name>
<url-pattern>/faces/system/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>Administrator</role-name>
</auth-constraint>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
<security-constraint>
<web-resource-collection>
<web-resource-name>CONFIDENTIAL resources - guest</web-resource-name>
<description>CONFIDENTIAL resources - guest</description>
<url-pattern>/faces/register.xhtml</url-pattern>
<url-pattern>/faces/login-form.xhtml</url-pattern>
</web-resource-collection>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
<security-role>
<role-name>*</role-name>
</security-role>
<login-config>
<auth-method>FORM</auth-method>
<form-login-config>
<form-login-page>/faces/login-form.xhtml</form-login-page>
<form-error-page>/faces/login-fail.xhtml</form-error-page>
</form-login-config>
</login-config>
</web-app>
5.2 login-form.xhtml
这是我们的登陆页面。
<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
template="/template/template.xhtml">
<ui:define name="title">
<h:outputText value="#{messages['ybxiang.javaarm.login']}" />
</ui:define>
<ui:define name="headMetaData">
</ui:define>
<ui:define name="body"><h:panelGroup layout="block" rendered="#{request.getUserPrincipal() == null}" >
<!--
(1) <form method="post" action="j_security_check">
http://javaarm.com/faces/j_security_check is used!
(2) <form method="post" action="#{request.contextPath}/j_security_check">
http://javaarm.com/j_security_check is used!
-->
<form method="post" action="j_security_check">
<table>
<tr>
<td width="10%">#{messages['ybxiang.javaarm.username']}:</td>
<td width="40%"><input type="text" name="j_username" /></td>
</tr>
<tr>
<td>#{messages['ybxiang.javaarm.password']}:</td>
<td><input type="password" name="j_password" /></td>
</tr>
<tr>
<td colspan="2"><input type="submit" value="#{messages['ybxiang.javaarm.login']}" /></td>
</tr>
</table>
</form>
</h:panelGroup>
</ui:define>
</ui:composition>
Comments