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
>>
>>
signature.asc
Description: OpenPGP digital signature
