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