alexedwards / scs

HTTP Session Management for Go
MIT License
2.13k stars 166 forks source link

Finding all sessions belonging to a specific user #86

Closed jeremija closed 3 years ago

jeremija commented 4 years ago

Thanks for this easy-to-use library!

What is the best way to select all sessions belonging to a specific user? I would like to provide a user with an interface to see and manage (log out of) any existing sessions.

At first I thought I'd implement my own Store and add a user_id int references "user"(id) column to the sessions table, but then the data passed to Store#Commit is already serialized so I would not be able to read the userID from the map.

Then I thought I'd add an extra step in my SetUserIDToSession and RemoveUserIDFromSession methods to associate a the user_id with a token in a separate table like:

create table "session_user"(
  token text not null references sessions(token) on delete cascade,
  user_id int references "user"(id) not null,
  primary key (token)
);

But I'm having a hard time implementing this because I do not see a way to get the current session token. I could read the cookie value, but what if the token was changed because the RenewToken method had been called beforehand?

Also, if the token had been renewed, the insert to session_user would fail because the token reference would not be in the sessions table yet (since the session is committed after the request handler).

The only hack I see at this point is to:

1) Use a local implementation of Codec because gobCodec is private. 2) Create a custom session Store. 3) Call Codec.Decode in my implementation of Store.Commit. 4) Read the user_id value from the map and use it to set sessions.user_id field in the db.

aight8 commented 4 years ago

I think this feature were really usefull. I don‘t see any session library which implement this.

alexedwards commented 4 years ago

I actually had to do something similar for a project a few months ago to revoke sessions for a specific user, and used a similar hack to the one that you suggest. Basically, I used a Codec implementation that marshaled the data to JSON, used the regular Postgres store without changing it, and then just queried the database directly to identify the sessions for a user.

If you're using Postgres, you could potentially write your own store implementation to use a JSON column in the database, which can then be indexed for fast direct querying.

jeremija commented 4 years ago

Thanks for your response! That's basically something similar to what I ended up doing. I kept the bytea type in the database, though. The only thing that seemed kind of hacky was that I had to call codec.Decode() in store.Commit() (which gets called immediately after codec.Encode() is made in this library), but it works!

alexedwards commented 4 years ago

As for supporting this functionality out-of-the-box, it's important to remember that sessions aren't just used for authentication and storing user information.

This is a general HTTP session management package, rather than an specific authentication package and user_id is just one arbitrary parameter that someone might want to store in a session.

So really, what we are talking about would require making the library support retrieval of sessions data from the database based on arbitrary parameters. I'll have a think about whether this is possible (or even sensible!), but my gut instinct in that it probably falls out of scope. Perhaps it would be possible to make it easier for people to achieve on their own somehow, though.

alexedwards commented 4 years ago

@jeremija I'm pleased that you got a work-around running!

alexedwards commented 3 years ago

After thinking about this further, my view hasn't really changed from the message above:

This is a general HTTP session management package, rather than an specific authentication package and user_id is just one arbitrary parameter that someone might want to store in a session.

So really, what we are talking about would require making the library support retrieval of sessions data from the database based on arbitrary parameters. I'll have a think about whether this is possible (or even sensible!), but my gut instinct in that it probably falls out of scope. Perhaps it would be possible to make it easier for people to achieve on their own somehow, though.

I think we could potentially make it easier by allowing you to iterate over all active sessions easily though, and that is probably something worth doing. There's an open issue https://github.com/alexedwards/scs/issues/92 for session enumeration already, so on that basis I'm going to close this one down.