问题
Our application has companies and uses in each company. Each company has X number of licenses. We are using a typed session class, and that class contains the id of the company along with other user information. I need to add to our authentication process, a check to see if the current login will exceed a company's licenses. I believe that the way to do this is to get a count of all company Ids across all sessions that match the companyId of the user currently trying to log in, and compare that count to the number of available licenses in our company table. Is this a valid approach? If so, please let me know how to query across all sessions, as I haven't figured it out and I'm still somewhat new to ServiceStack.
回答1:
Using ICacheClientExtended API's
The ICacheClientExtended
interface now supports a GetKeysByPattern
API that lets you scan for matching keys on Cache Clients that implement the interface. Currently this is implemented by:
- MemoryCacheClient
- OrmLiteCacheClient
- Redis
- AWS DynamoDbCacheClient
This API now enables the new GetAllKeys()
and GetKeysStartingWith()
extension methods now available on ICacheClient
to scan all cache keys.
var prefix = IdUtils.CreateUrn<IAuthSession>(""); //= urn:iauthsession:
var sessionKeys = Cache.GetKeysStartingWith(sessionPattern).ToList();
var userSessions = Cache.GetValues<AuthUserSession>(sessionKeys);
var existingSessions = userSessions.Values.Where(x => x != null).ToList();
Where existingSessions
will contain list of active User Sessions.
Performance will be determined by how many active sessions you have which could be high depending on popularity of your site. Instead of searching all keys you may want to keep a set of session ids per company that you would look through instead by adding them to a collection in a Session or Auth Event.
This new API is available from v4.0.45+ of ServiceStack that's now available on MyGet.
The latest DynamoDbCacheClient is now in the new ServiceStack.Aws NuGet package on MyGet which references the latest v3.* packages from the AWS SDK.
Searching the underlying Caching Provider
Another option is access them directly from your ICacheClient
Caching provider if it supports full scans, e.g. if you're using OrmLiteCacheClient
to store sessions in an RDBMS you can access all Cache Entries with:
var sessionEntries = Db.Select<CacheEntry>(q =>
q.Where(x => x.Id.StartsWith("urn:iauthsession:")));
var userSessions = sessionEntries.Map(x =>
Db.Deserialize<AuthUserSession>(x.Data));
If you're using Redis for Caching you can get it with:
var sessionKeys = Redis.SearchKeys("urn:iauthsession:*");
var sessions = Redis.GetValues<AuthUserSession>(sessionKeys);
Another option would be to maintain a list of all Session Ids for each Company as each user logs in by registering a custom Session or Auth Event which you could maintain in a Redis SET or RDBMS table. In the same registration hook you can verify how many active Sessions they have by using ICacheClient.GetAll
API and passing in the session keys for that company, something like:
var sessions = Cache.GetAll<AuthUserSession>(companySessionKeys);
var activeSessions = sessions.Values.Where(x => x != null).ToList();
回答2:
A little speed check:
I am using InMemoryAuthRepository, and if I have 1000 sessions in cache, and I fetch them, it takes 21 ms. The fetching starts at 4 ms (for 1 session) and goes up to 21 ms for a 1000.
sw.Restart();
IDictionary<string, IAuthSession> sessionList = cacheClient?.GetAll<IAuthSession>(cacheClient?.GetAllKeys());
sw.Stop();
totalMs += sw.ElapsedMilliseconds;
counter2speed.Add(counter, totalMs);
来源:https://stackoverflow.com/questions/32459285/how-do-i-iterate-across-all-sessions-in-servicestack