All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cc.protea.platform.SessionUtilRedis Maven / Gradle / Ivy

package cc.protea.platform;

import cc.protea.foundation.integrations.RedisUtil;
import cc.protea.foundation.integrations.RedisUtil.WithJedis;
import cc.protea.foundation.integrations.RedisUtil.WithJedisNull;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Transaction;

import java.util.Set;

/**
 * Within Redis the following areas are maintained:
 *
 *  sessions            - zset - session expiration date in ms; MAX if session does not expire
 *  sessions:TOKEN      - hash - { userId, expireSeconds }
 *  users:sessions      - zset - userId is the score, session token is the value
 */
class SessionUtilRedis {
	
	private static final Integer TTL_SECONDS = 60 * 60 * 24 * 30; // One month
	
	/**
	 * Searches for a user associated with the token. If one is found user has a session and is authenticated.
	 * Will automatically retry one time if there's any issue. Any further exceptions are thrown upstream.
	 * @param token
	 * @return Authenticated user id
	 */
	static Long getUserId(final String token) {
		try {
			return getUserIdInternal(token);
		} catch (Exception e) {
			return getUserIdInternal(token);
		}
	}

	static Long getUserIdInternal(final String token) {
		return RedisUtil.execute(new WithJedis() { public Long process(final Jedis jedis) {
			// fetch the user for this session
			String userString = jedis.get("sessions:active:" + StringUtils.trim(token));
			if (! StringUtils.isNumeric(userString)) {
				return null;
			}
			// refresh the expiry
			jedis.expireAt("sessions:" + StringUtils.trim(token), TTL_SECONDS);
			//jedis.zadd("sessions", new Date().getTime(), StringUtils.trim(token));
			return NumberUtils.createLong(userString);
		}});
	}

	static void create(final Long userId, final String token) {
		RedisUtil.jedis(new WithJedisNull() { public void process(final Jedis jedis) {
			Transaction t = jedis.multi();
			t.setex("sessions:active:" + token, TTL_SECONDS, userId.toString());	// Add sessions: key with ttl
			t.zadd("sessions", Double.MAX_VALUE, token);	// Add token to bottom of the sessions sorted set (Do we need this?)
			t.zadd("users:sessions", userId, token);		// associate token and userid in a way we can easily look up
			t.exec();
		}});
	}

	static void remove(final String token) {
		if (token == null) {
			return;
		}
		final String trimmed = StringUtils.trim(token);
		RedisUtil.jedis(new WithJedisNull() { public void process(final Jedis jedis) {
			Transaction t = jedis.multi();
			t.zrem("sessions", trimmed);
			t.del("sessions:active:" + trimmed);
			t.zrem("users:sessions", trimmed);
			t.exec();
		}});
	}

	static void removeAllForUser(final Long userId) {
		Set sessions = RedisUtil.execute(new WithJedis>() { public Set process(final Jedis jedis) {
			return jedis.zrangeByScore("users:sessions", userId, userId);
		}});
		for (String session : sessions) {
			SessionUtil.remove(session);
		}
	}

	static Set getAllForUser(final Long userId) {
		if (userId == null) {
			return null;
		}
		return RedisUtil.execute(new WithJedis>() { public Set process(final Jedis jedis) {
			return jedis.zrangeByScore("users:sessions", userId, userId);
		}});
	}


}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy