I want to create a simple web application that will have self-registering users. In other words, I want users to be able to register, log on, manage their data, log off, and if they want, delete their account. It is kind of a hobby project and just to learn something new, I decided to try to create this web site using latest Java EE, which I have not used before.
I spent several hours reading about JAAS, authentication realms, etc and I found lots of ways to implement security based on users and roles defined on the server (like GlassFish), but I have not found any examples or pointers to how to implement a solution where users can just fill out a registration form on a web page and become users in the system. Of course, I can simple have a database table with usernames and password hashes and implement everything manually, but it defeats the purpose.
Therefore, my questions are:
- Is Java EE's standard authentication and security framework suitable for implementing an app where users can manage themselves? Or is it more "enterprise" and relies on externa开发者_JAVA百科l authentication and user management?
- If it is easy to do what I need, please point me to some samples.
Thanks!
The J2EE is not very good at this. I have done that in an application though. I have a table of users in the (only) database used by my application, and I have declared a realm in the context.xml file in the META-INF directory of the webapp (I'm using tomcat btw):
<Realm className="org.apache.catalina.realm.DataSourceRealm"
dataSourceName="jdbc/fantastico" debug="99" localDataSource="true"
digest="MD5" roleNameCol="ROLE" userCredCol="PASSWORD"
userNameCol="USERNAME" userRoleTable="user_roles"
userTable="active_users"/>
the datasource is the same as the one used in the rest of the application and is declared in the server.xml of the tomcat installation (so that I can point to another db without changing the .war file).
I have protected locations with roles in the web.xml file, making sure I have left the registration page and the login page uprotected:
<security-constraint>
<display-name>Administrators</display-name>
<web-resource-collection>
<web-resource-name>admin</web-resource-name>
<description>Admin</description>
<url-pattern>/admin</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
<http-method>HEAD</http-method>
<http-method>PUT</http-method>
<http-method>OPTIONS</http-method>
<http-method>TRACE</http-method>
<http-method>DELETE</http-method>
</web-resource-collection>
<auth-constraint>
<description>Allow access only to administrators</description>
<role-name>admin</role-name>
</auth-constraint>
</security-constraint>
I have specified a <login-config> section with FORM as the auth method:
<login-config>
<auth-method>FORM</auth-method>
<realm-name/>
<form-login-config>
<form-login-page>/login/</form-login-page>
<form-error-page>/login/error</form-error-page>
</form-login-config>
</login-config>
Since the realm is declared as using an MD5 digest, it's the MD5 of the password that must be store in the database:
private static final char HEX[] = "0123456789abcdef".toCharArray();
public static String hex(byte data[]) {
char[] chars = new char[2*data.length];
for (int i=0; i < data.length; i++) {
int low = data[i] & 0x0f;
int high = (data[i] & 0xf0) >> 4;
chars[i*2] = HEX[high];
chars[i*2 + 1] = HEX[low];
}
return new String(chars);
}
public static byte[] hash(byte data[]) {
synchronized (DIGEST) {
DIGEST.reset();
return DIGEST.digest(data);
}
}
public static String hash(String value) {
try {
byte data[] = hash(value.getBytes("UTF-8"));
return hex(data);
} catch (UnsupportedEncodingException e) {
// Cannot happen: UTF-8 support is required by Java spec
LOG.error("Failed to generate digest", e);
throw new RuntimeException(e.getMessage());
}
}
In the login form, that tomcat will display whenever an authentication is required, I have added a link to the registration form:
...
<form id="login-form" action="j_security_check" method="post">
<table>
<tbody>
<tr>
<td><label for="username">User name: </label></td>
<td><input type="text" name="j_username" id="username" /></td>
</tr>
<tr>
<td><label for="password">Password: </label></td>
<td><input type="password" name="j_password" id="password" /></td>
</tr>
<tr>
<td> </td>
<td><input type="submit" id="submit" name="submit" value="Login"></td>
</tr>
<tr>
<td> </td>
<td><a href="../reg/create">I'm a new user</a></td>
</tr>
</tbody>
</table>
</form>
...
Now, when the registration form is submitted, I store the user in the database, and I send a redirect to automatically log the user in:
...
response.sendRedirect(request.getContextPath()
+ "/j_security_check?j_username="
+ URLEncoder.encode(getEmail(), "UTF-8")
+ "&j_password="
+ URLEncoder.encode(password, "UTF-8"));
...
Hope this will help
As an alternative you might want to have a look at the Spring Security framework. I have used it with my Grails projects in the way that you have described, with users signing up by themselves and I have found it to be easy to use.
精彩评论