Here's the code.  Two pretty simple classes.  The one thing that I
wasn't sure about was the timeout methods in the session - I'm fairly
certain that they're irrelevant in this situation, so I've basically not
implemented them.  Hopefully the wrapping doesn't screw this up too much
- if there's somewhere better to post this stuff, please let me know.

Thanks,
Jared

/**
 * Intended to keep session request-scoped and therefore not persist
them across multiple requests - a user must login
 * on each request. This necessarily means that a mechanism like
form-based authentication isn't viable, but the
 * intention is primarily for uses in stateless apis.
 */
public class HttpRequestSessionManager implements SessionManager
{

        static final String REQUEST_ATTRIBUTE_KEY = "__SHIRO_REQUEST_SESSION";

        @Override
        public Session start(SessionContext context) throws 
AuthorizationException
        {
                if (!WebUtils.isHttp(context))
                {
                        String msg = "SessionContext must be an HTTP compatible 
implementation.";
                        throw new IllegalArgumentException(msg);
                }

                HttpServletRequest request = WebUtils.getHttpRequest(context);

                String host = getHost(context);

                Session session = createSession(request, host);
                request.setAttribute(REQUEST_ATTRIBUTE_KEY, session);

                return session;
        }

        @Override
        public Session getSession(SessionKey key) throws SessionException
        {
                if (!WebUtils.isHttp(key))
                {
                        String msg = "SessionKey must be an HTTP compatible 
implementation.";
                        throw new IllegalArgumentException(msg);
                }

                HttpServletRequest request = WebUtils.getHttpRequest(key);

                return (Session) request.getAttribute(REQUEST_ATTRIBUTE_KEY);
        }

        private String getHost(SessionContext context)
        {
                String host = context.getHost();
                if (host == null)
                {
                        ServletRequest request = WebUtils.getRequest(context);
                        if (request != null)
                        {
                                host = request.getRemoteHost();
                        }
                }
                return host;

        }

        protected Session createSession(HttpServletRequest request, String host)
        {
                return new HttpServletRequestSession(request, host);
        }

}

/**
 * Session that is only tied to an HttpServletRequest. This can be used
for applications that prefer to remain stateless.
 */
public class HttpServletRequestSession implements Session
{
        private HttpServletRequest request;
        private String host;
        private UUID uuid;
        private Date start;

        public HttpServletRequestSession(HttpServletRequest request, String 
host)
        {
                this.request = request;
                this.host = host;
                this.uuid = UUID.randomUUID();
                this.start = new Date();
        }

        @Override
        public Serializable getId()
        {
                return uuid;
        }

        @Override
        public Date getStartTimestamp()
        {
                return start;
        }

        @Override
        public Date getLastAccessTime()
        {
                // the user only makes one request that involves this session
                return start;
        }

        @Override
        public long getTimeout() throws InvalidSessionException
        {
                return -1;
        }

        @Override
        public void setTimeout(long maxIdleTimeInMillis) throws
InvalidSessionException
        {
                // ignore this - the session ends with the request and that's 
that...
        }

        @Override
        public String getHost()
        {
                return host;
        }

        @Override
        public void touch() throws InvalidSessionException
        {
                // do nothing - we don't timeout
        }

        @Override
        public void stop() throws InvalidSessionException
        {
                // do nothing - i don't have a use case for this and the 
structure to
support it, while not huge, adds
                // significant complexity
        }

        @SuppressWarnings( { "unchecked" })
        @Override
        public Collection<Object> getAttributeKeys() throws 
InvalidSessionException
        {
                return EnumerationUtils.toList(request.getAttributeNames());
        }

        @Override
        public Object getAttribute(Object key) throws InvalidSessionException
        {
                return request.getAttribute(stringify(key));
        }

        @Override
        public void setAttribute(Object key, Object value) throws
InvalidSessionException
        {
                request.setAttribute(stringify(key), value);
        }

        @Override
        public Object removeAttribute(Object objectKey) throws
InvalidSessionException
        {
                String key = stringify(objectKey);
                Object formerValue = request.getAttribute(key);
                request.removeAttribute(key);
                return formerValue;
        }

        private String stringify(Object key)
        {
                return key == null ? null : key.toString();
        }
}



On 02/17/2011 09:12 AM, Tamás Cservenák wrote:
> Hi Jared,
> 
> yes, that's my conclusion -- at least in REST world -- that Shiro 
> sessions are <em>great</em> benefit for Java systems (from Javadoc
> ;) and I do want to use them. And what you did intrigues my
> imagination, since in "my" solution, a lot of moving parts (Http
> Servlet container, etc) are triggered just for nothing, to achieve
> exactly what you did: to have session lifespan equal to the
> request's.
> 
> This is something Shiro should support IMO.
> 
> +1 for seeing that piece of code :)
> 
> 
> Thanks, ~t~
> 
> On Thu, Feb 17, 2011 at 3:30 PM, Jared Bunting 
> <[email protected]> wrote:
>> Tamás,
>> 
>> I've encountered the same problem and approached it in a slightly 
>> different way.  Basically, I created my own implementation of 
>> SessionManager and Session that are backed only by the 
>> HttpServletRequest.  Each session's lifecycle is tied to the
>> request.
>> 
>> I'd also be interested in criticism of this approach, or if anyone
>> is interested in seeing the code I'd be happy to share it.
>> 
>> Thanks, Jared
>> 
>> 


Attachment: signature.asc
Description: OpenPGP digital signature

Reply via email to