I'm looking for some opinions on how to best implement a custom UserDetails when creating a custom PasswordAuthenticationDao especially when using Hibernate. My existing User domain model looks like this:
And I'll be adding a lot more later.Code:/** * @author kuato * * @hibernate.class table="users" */ public class User implements Serializable { private Long id = null; private int version; /* managed version */ private String username; private String password; private String email; private boolean enabled; private Date created; private Date lastVisit; private Set roles; /* gettors and settors here */ }
My first thought was to have User implement UserDetails but that didn't sit too well with me so I came up with a separate class and called it AuthenticatedUser which extends net.sf.acegisecurity.providers.dao.User(which of course implements UserDetails) like this:
This way I can keep just the bare details about a user in the SecureContext.Code:public class AuthenticatedUser extends net.sf.acegisecurity.providers.dao.User { private long id; private String email; public AuthenticatedUser(long userId, String email, String username, String password, boolean enabled, GrantedAuthority[] authorities) throws IllegalArgumentException { super(username, password, enabled, authorities); this.id = userId; this.email = email; } }
And in my custom PasswordAuthenticationDao the code looks like this to read in the roles:
And finally when a user navigates to a secure area where he/she can do something like add a new article/news/photo then I need to load the user object and add it to the association sort of like this in my GalleryAddPhotoFormController:Code:public class UserAuthenticationDaoImpl implements PasswordAuthenticationDao { protected final Log logger = LogFactory.getLog(getClass()); private IUserManagerFacade userManager = null; public void setUserManager(IUserManagerFacade userManager) { this.userManager = userManager; } public UserDetails loadUserByUsernameAndPassword(String username, String password) throws DataAccessException, BadCredentialsException { UserDetails userDetails = null; if (this.userManager != null) { User user = this.userManager.findUserByUsernameAndPassword(username, password); if (user != null) { Set roles = user.getRoles(); Iterator it = roles.iterator(); GrantedAuthority[] authorities = new GrantedAuthority[roles.size()]; int i = 0; while (it.hasNext()) { Role role = (Role)it.next(); authorities[i++] = new GrantedAuthorityImpl(role.getName()); } logger.info("authorities= " + authorities); userDetails = new AuthenticatedUser(user.getId().longValue(), user.getEmail(), user.getUsername(), user.getPassword(), user.getEnabled(), authorities); } else { throw new BadCredentialsException("Bad Credentials Presented"); } } return userDetails; } }
Is this a good practice? This keeps my User domain model loosely coupled from Acegi Security. I also don't like the idea of keeping a hibernate User object in the SecureContext the whole time. Just wondering what other people have done and what your experience has been.Code:GalleryPhoto photo = new GalleryPhoto(); AuthenticatedUser authUser = (AuthenticatedUser)((SecureContext)ContextHolder.getContext()).getAuthentication().getPrincipal(); User user = (User)this.userManager.findUserById((long)authUser.getId()); photo.setUser(user); this.galleryManager.insertPhoto(photo);
So far I just love Acegi Security. I just need to tackle the ACL permissions next.
Thanks for listening.



