Commit 0b0a00d4 authored by Akshay Bharambe's avatar Akshay Bharambe
Browse files

Add: Docs

parent b83dc523
Branches kunal_SQLServer
Tags
2 merge requests!210Staging mepdeployment05072020,!200Add: Session control
Showing with 62 additions and 36 deletions
// package sessionmdl provides APIs to Add, Validate and Delete user sessions. These APIs must be used along with JWT Auth.
// If you want to use this functionality, a jwt token must contain `userId` and `sessionId` fields.
// A user can have multiple active sessions for different use cases. To check if user has an active session for particular usecase use `CheckForSessionAvailability()`.
// And to check user session on each request use `ValidateSessionFromToken()`.
//
// An in memory cache is used to store sessions. It automatically falls back to redis cache if -gridmode=1 is set.
//
// An `SessionInstance` is assigned a new ID on application start. Its users responsibility to send this value in `InstanceHeader` on each request, other than open.
// The expiraion of session must be same as of token expiration.
package sessionmdl
import (
"errors"
"log"
"time"
"coresls/servers/coresls/app/models"
"corelab.mkcl.org/MKCLOS/coredevelopmentplatform/corepkgv2/cachemdl"
"corelab.mkcl.org/MKCLOS/coredevelopmentplatform/corepkgv2/utiliymdl/guidmdl"
"github.com/dgrijalva/jwt-go"
)
type Session struct {
// UserID string
SessionFor string
SessionID string
SessionId string
}
const (
// InstanceHeader is used because we need to ensure that the request is from outdated instance.
// Ex. When the application restarts, it may get request from client which has previous `SessionInstance`
InstanceHeader = "session-instance"
)
// ValidateSession is used to give user flexibility to use or not to use this feature.
// The set this on app start if you want to use session validation.
var ValidateSession bool
// SessionInstance is used to differentiate between current and previous instances. This must be set in client and sent in each request against `session-instance` header.
var SessionInstance = guidmdl.GetGUID()
// store is used to store sessions in memory, falls back to redis cache on grid mode.
var store cachemdl.Cacher
var (
......@@ -53,30 +67,38 @@ func InitSessionManagerCache(chacheType int) {
store = cachemdl.GetCacheInstance(&cacheConfig)
}
func Set(userID string, s ...Session) {
i, _ := store.Get(userID)
if i == nil {
store.Set(userID, s)
// Set stores the sessions for provided userId. Session is appended to the list. It does not check if the same session exists or not.
func Set(userId string, s ...Session) {
i, ok := store.Get(userId)
if !ok || i == nil {
set(userId, s)
log.Println("Set new user")
return
}
sessions, ok := i.([]Session)
if !ok {
store.Set(userID, s)
set(userId, s)
return
}
store.Set(userID, append(sessions, s...))
set(userId, append(sessions, s...))
}
func set(key string, val interface{}) {
// Set the user sessions with no expiry as each session can have different expiry depending on the JWT token expiry.
store.SetNoExpiration(key, val)
}
func Get(userID string) ([]Session, error) {
// Get returns all the available sessions for the user. This may contain expired but not deleted sessions.
func Get(userId string) ([]Session, error) {
var (
s []Session
i interface{}
ok bool
)
i, ok = store.Get(userID)
i, ok = store.Get(userId)
if !ok {
return s, ErrSessionNotFound
}
......@@ -89,12 +111,37 @@ func Get(userID string) ([]Session, error) {
return s, nil
}
// Delete removes all the sessions associated with the user.
func Delete(userId string) {
store.Delete(userId)
}
// ValidateSessionFromToken checks for session id in claims against available sessions
func ValidateSessionFromToken(claims jwt.MapClaims) error {
// DeleteSession removes a particular session for user, if present.
func DeleteSession(userId, sessionFor string) {
sessions, err := Get(userId)
if err != nil {
return
}
for i := 0; i < len(sessions); i++ {
if sessions[i].SessionFor == sessionFor {
sessions[i] = sessions[len(sessions)-1]
sessions = sessions[:len(sessions)-1]
}
}
if len(sessions) == 0 {
store.Delete(userId)
return
}
set(userId, sessions)
}
// ValidateSessionFromToken checks for session id in claims against available sessions.
// The claims must contain `userId` and `sessionId` fields.
func ValidateSessionFromToken(claims map[string]interface{}) error {
i, ok := claims["userId"]
if !ok {
return errors.New("\"userId\" field not found in token")
......@@ -123,7 +170,7 @@ func ValidateSessionFromToken(claims jwt.MapClaims) error {
var found bool
for i := range sessions {
if sessions[i].SessionID == sessionId {
if sessions[i].SessionId == sessionId {
found = true
break
}
......@@ -136,6 +183,7 @@ func ValidateSessionFromToken(claims jwt.MapClaims) error {
return nil
}
// CheckForSessionAvailability checks if the user has active session for provided `sessionFor`.
func CheckForSessionAvailability(userId, sessionFor string) error {
sessions, err := Get(userId)
......@@ -158,25 +206,3 @@ func CheckForSessionAvailability(userId, sessionFor string) error {
return nil
}
func DeleteSession(userId, sessionFor string) {
sessions, err := Get(userId)
if err != nil {
return
}
for i := 0; i < len(sessions); i++ {
if sessions[i].SessionFor == sessionFor {
sessions[i] = sessions[len(sessions)-1]
sessions = sessions[:len(sessions)-1]
}
}
if len(sessions) == 0 {
store.Delete(userId)
return
}
store.Set(userId, sessions)
}
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment