You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@shiro.apache.org by Les Hazlewood <lh...@apache.org> on 2009/06/27 21:38:27 UTC

Re: wicket-ki-security

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

Re: wicket-ki-security

Posted by Tauren Mills <yo...@gmail.com>.
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 <lh...@apache.org>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
>
>
>