Les, Thanks for posting this to the user list and your suggestions. The wicket-shiro project already had UserService implemented the way you suggested, but I just wasn't using it effectively in UserAuthHeader. I've updated the UserAuthHeader to call getCurrentUser(). I have not added a ShiroService to the wicket-shiro sample, but I can see how it would prove useful in a real project. Perhaps I'll add it to the sample later.
So I'm curious about the status of getting Shiro into a maven repository. Any estimates on when that might happen? Thanks! Tauren On Sat, Jun 27, 2009 at 12:38 PM, Les Hazlewood <[email protected]>wrote: > Hi Tauren, > > I'm forwarding this to the Shiro user list as the answer could benefit > other people as well. > > The User object itself should probably never be stored in the Subject or > its Session - just the ID as you've pointed out. This is definitely the > appropriate way to use Shiro for most enterprise applications. > > The reason is that, especially with JPA/Hibernate applications, If Shiro > stored the User object directly, it would bypass lots of optimizations that > are in place in persistence frameworks, such as caching. > > That is, you should almost always lookup the User object during a > transaction via the Subject-accessible user ID, and rely on a nice caching > framework to improve performance if you don't want an expensive 'round trip' > to the database each time you do the lookup. > > This is especially important for coherency - if you cache a User object in > the Subject (or the Subject's Session), and you change that User object > somewhere else in the application (say, via an 'update account' web page), > well, now the User object in your session is 'stale' and does not reflect > the one changed by visiting the 'update account' web page. > > This beneficial technique is not unique to just Shiro of course - most > session values should usually be extremely lightweight objects - ids or > lookup keys to pull the corresponding 'real' object via a Service or DAO > call, relying on the underlying persistence framework and caching to help > with performance, data versioning, coherency, etc. > > So a good practice is to have a 'utility' helper component that can do this > translation automatically. > > For example, UserService#getCurrentUser(): > > public User getCurrentUser() { > Long id = (Long)SecurityUtils.getSubject().getPrincipal(); > if ( id != null ) { > // they are either authenticated or remembered from a previous > session, > // so return the user: > return getUser(id); > } else { > //not logged in or remembered: > return null; > } > } > > I've taken this concept a little further and I wrap all my > SecurityUtils.getSubject().* method operations by creating a SubjectService > interface: > > public interface SubjectService { > > User getCurrentUser(); > > hasRole(String role); > > isPermitted(String permission); > > //more Subject 'wrapper' methods as necessary > > setSessionAttribute(Object key, Object value); > removeSessionAttribute(key); > > //etc.. > } > > Then you would write a ShiroSubjectService implementation of this > interface that calls the Shiro SecurityUtils/Subject API. > > The benefit here is that all of your code deals with the SubjectService for > everything, and never needs to 'know about', i.e. import any of Shiro's > APIs - very loosely coupled. Granted, you wouldn't need to use such an > abstraction for wicket-shiro integration, but this approach is very useful > in enterprise applications where you want to decouple you and your > programming team from any 3rd party APIs as best as possible. > > I hope that helps! > > Cheers, > > Les > > > On Sat, Jun 27, 2009 at 12:52 PM, Tauren Mills wrote: > >> Les, >> >> Just wanted to let you know I renamed the project to wicket-shiro. I also >> added a spring/hibernate example to it. But I was wondering if I should be >> getting the username out of the subject in a better way than this: >> >> @SpringBean(name = "userService") >> private UserService userService; >> >> public UserAuthHeader(String id, Class<? extends Page> loginPage) >> { >> super( id ); >> >> add( new Label( "name", new AbstractReadOnlyModel<String>() { >> @Override >> public String getObject() { >> Long id = (Long) SecurityUtils.getSubject().getPrincipal(); >> return userService.getUser(id).getUsername(); >> } >> }) ); >> } >> >> With the user being a Hibernate User entity, the principle is a Long id. >> So I'm using that to find the User from the userService and return the >> username. But is the User object stored in the Subject somewhere? I didn't >> locate it when I was tracing the code. >> >> See here for the full java file: >> >> https://wicket-stuff.svn.sourceforge.net/svnroot/wicket-stuff/trunk/wicketstuff-core/shiro-security/wicket-shiro-examples/shiro-example-spring-hibernate/src/main/java/org/wicketstuff/shiro/example/sprhib/UserAuthHeader.java >> >> Thanks! >> Tauren > > >
