Feat/multiple session (#64)
* fix: disable windows build * feat: add ability to handle multiple sessions
This commit is contained in:
parent
4649391169
commit
b69d0b8e23
13
.github/workflows/release.yaml
vendored
13
.github/workflows/release.yaml
vendored
|
@ -36,12 +36,12 @@ jobs:
|
||||||
run: echo VERSION=$(basename ${GITHUB_REF}) >> ${GITHUB_ENV}
|
run: echo VERSION=$(basename ${GITHUB_REF}) >> ${GITHUB_ENV}
|
||||||
- name: Copy .env file
|
- name: Copy .env file
|
||||||
run: mv .env.sample .env
|
run: mv .env.sample .env
|
||||||
- name: Package files for windows
|
# - name: Package files for windows
|
||||||
run: |
|
# run: |
|
||||||
make clean && \
|
# make clean && \
|
||||||
CGO_ENABLED=1 GOOS=windows CC=/usr/bin/x86_64-w64-mingw32-gcc make && \
|
# CGO_ENABLED=1 GOOS=windows CC=/usr/bin/x86_64-w64-mingw32-gcc make && \
|
||||||
mv build/server build/server.exe && \
|
# mv build/server build/server.exe && \
|
||||||
zip -vr authorizer-${VERSION}-windows-amd64.zip .env app/build build templates
|
# zip -vr authorizer-${VERSION}-windows-amd64.zip .env app/build build templates
|
||||||
- name: Package files for linux
|
- name: Package files for linux
|
||||||
run: |
|
run: |
|
||||||
make clean && \
|
make clean && \
|
||||||
|
@ -49,7 +49,6 @@ jobs:
|
||||||
tar cvfz authorizer-${VERSION}-linux-amd64.tar.gz .env app/build build templates
|
tar cvfz authorizer-${VERSION}-linux-amd64.tar.gz .env app/build build templates
|
||||||
- name: Upload assets
|
- name: Upload assets
|
||||||
run: |
|
run: |
|
||||||
github-assets-uploader -f authorizer-${VERSION}-windows-amd64.zip -mediatype application/zip -repo authorizerdev/authorizer -token ${{secrets.RELEASE_TOKEN}} -tag ${VERSION} && \
|
|
||||||
github-assets-uploader -f authorizer-${VERSION}-linux-amd64.tar.gz -mediatype application/gzip -repo authorizerdev/authorizer -token ${{secrets.RELEASE_TOKEN}} -tag ${VERSION}
|
github-assets-uploader -f authorizer-${VERSION}-linux-amd64.tar.gz -mediatype application/gzip -repo authorizerdev/authorizer -token ${{secrets.RELEASE_TOKEN}} -tag ${VERSION}
|
||||||
- name: Log in to Docker Hub
|
- name: Log in to Docker Hub
|
||||||
uses: docker/login-action@v1
|
uses: docker/login-action@v1
|
||||||
|
|
6
TODO.md
6
TODO.md
|
@ -1,5 +1,11 @@
|
||||||
# Task List
|
# Task List
|
||||||
|
|
||||||
|
## Feature Multiple sessions
|
||||||
|
|
||||||
|
- Multiple sessions for users to login use hMset from redis for this
|
||||||
|
user_id access_token1 long_live_token1
|
||||||
|
user_id access_token2 long_live_token2
|
||||||
|
|
||||||
# Feature roles
|
# Feature roles
|
||||||
|
|
||||||
For the first version we will only support setting roles master list via env
|
For the first version we will only support setting roles master list via env
|
||||||
|
|
|
@ -27,6 +27,7 @@ type Manager interface {
|
||||||
GetVerificationByEmail(email string) (VerificationRequest, error)
|
GetVerificationByEmail(email string) (VerificationRequest, error)
|
||||||
DeleteUser(email string) error
|
DeleteUser(email string) error
|
||||||
SaveRoles(roles []Role) error
|
SaveRoles(roles []Role) error
|
||||||
|
SaveSession(session Session) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type manager struct {
|
type manager struct {
|
||||||
|
@ -56,7 +57,7 @@ func InitDB() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal("Failed to init db:", err)
|
log.Fatal("Failed to init db:", err)
|
||||||
} else {
|
} else {
|
||||||
db.AutoMigrate(&User{}, &VerificationRequest{}, &Role{})
|
db.AutoMigrate(&User{}, &VerificationRequest{}, &Role{}, &Session{})
|
||||||
}
|
}
|
||||||
|
|
||||||
Mgr = &manager{db: db}
|
Mgr = &manager{db: db}
|
||||||
|
|
39
server/db/session.go
Normal file
39
server/db/session.go
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
package db
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
"gorm.io/gorm/clause"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Session struct {
|
||||||
|
ID uuid.UUID `gorm:"type:uuid;"`
|
||||||
|
UserID uuid.UUID `gorm:"type:uuid;"`
|
||||||
|
User User
|
||||||
|
UserAgent string
|
||||||
|
IP string
|
||||||
|
CreatedAt int64 `gorm:"autoCreateTime"`
|
||||||
|
UpdatedAt int64 `gorm:"autoUpdateTime"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Session) BeforeCreate(tx *gorm.DB) (err error) {
|
||||||
|
r.ID = uuid.New()
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// SaveSession function to save user sessiosn
|
||||||
|
func (mgr *manager) SaveSession(session Session) error {
|
||||||
|
res := mgr.db.Clauses(
|
||||||
|
clause.OnConflict{
|
||||||
|
DoNothing: true,
|
||||||
|
}).Create(&session)
|
||||||
|
if res.Error != nil {
|
||||||
|
log.Println(`Error saving session`, res.Error)
|
||||||
|
return res.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -30,6 +30,7 @@ func (mgr *manager) AddVerification(verification VerificationRequest) (Verificat
|
||||||
Columns: []clause.Column{{Name: "email"}},
|
Columns: []clause.Column{{Name: "email"}},
|
||||||
DoUpdates: clause.AssignmentColumns([]string{"token", "identifier", "expires_at"}),
|
DoUpdates: clause.AssignmentColumns([]string{"token", "identifier", "expires_at"}),
|
||||||
}).Create(&verification)
|
}).Create(&verification)
|
||||||
|
|
||||||
if result.Error != nil {
|
if result.Error != nil {
|
||||||
log.Println(`Error saving verification record`, result.Error)
|
log.Println(`Error saving verification record`, result.Error)
|
||||||
return verification, result.Error
|
return verification, result.Error
|
||||||
|
|
|
@ -147,11 +147,11 @@ func OAuthCallbackHandler() gin.HandlerFunc {
|
||||||
provider := c.Param("oauth_provider")
|
provider := c.Param("oauth_provider")
|
||||||
state := c.Request.FormValue("state")
|
state := c.Request.FormValue("state")
|
||||||
|
|
||||||
sessionState := session.GetToken(state)
|
sessionState := session.GetSocailLoginState(state)
|
||||||
if sessionState == "" {
|
if sessionState == "" {
|
||||||
c.JSON(400, gin.H{"error": "invalid oauth state"})
|
c.JSON(400, gin.H{"error": "invalid oauth state"})
|
||||||
}
|
}
|
||||||
session.DeleteToken(sessionState)
|
session.RemoveSocialLoginState(state)
|
||||||
// contains random token, redirect url, role
|
// contains random token, redirect url, role
|
||||||
sessionSplit := strings.Split(state, "___")
|
sessionSplit := strings.Split(state, "___")
|
||||||
|
|
||||||
|
@ -254,7 +254,16 @@ func OAuthCallbackHandler() gin.HandlerFunc {
|
||||||
|
|
||||||
accessToken, _, _ := utils.CreateAuthToken(user, enum.AccessToken, inputRoles)
|
accessToken, _, _ := utils.CreateAuthToken(user, enum.AccessToken, inputRoles)
|
||||||
utils.SetCookie(c, accessToken)
|
utils.SetCookie(c, accessToken)
|
||||||
session.SetToken(userIdStr, refreshToken)
|
session.SetToken(userIdStr, accessToken, refreshToken)
|
||||||
|
go func() {
|
||||||
|
sessionData := db.Session{
|
||||||
|
UserID: user.ID,
|
||||||
|
UserAgent: utils.GetUserAgent(c.Request),
|
||||||
|
IP: utils.GetIP(c.Request),
|
||||||
|
}
|
||||||
|
|
||||||
|
db.Mgr.SaveSession(sessionData)
|
||||||
|
}()
|
||||||
|
|
||||||
c.Redirect(http.StatusTemporaryRedirect, redirectURL)
|
c.Redirect(http.StatusTemporaryRedirect, redirectURL)
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,18 +51,18 @@ func OAuthLoginHandler() gin.HandlerFunc {
|
||||||
|
|
||||||
switch provider {
|
switch provider {
|
||||||
case enum.Google.String():
|
case enum.Google.String():
|
||||||
session.SetToken(oauthStateString, enum.Google.String())
|
session.SetSocailLoginState(oauthStateString, enum.Google.String())
|
||||||
// during the init of OAuthProvider authorizer url might be empty
|
// during the init of OAuthProvider authorizer url might be empty
|
||||||
oauth.OAuthProvider.GoogleConfig.RedirectURL = constants.AUTHORIZER_URL + "/oauth_callback/google"
|
oauth.OAuthProvider.GoogleConfig.RedirectURL = constants.AUTHORIZER_URL + "/oauth_callback/google"
|
||||||
url := oauth.OAuthProvider.GoogleConfig.AuthCodeURL(oauthStateString)
|
url := oauth.OAuthProvider.GoogleConfig.AuthCodeURL(oauthStateString)
|
||||||
c.Redirect(http.StatusTemporaryRedirect, url)
|
c.Redirect(http.StatusTemporaryRedirect, url)
|
||||||
case enum.Github.String():
|
case enum.Github.String():
|
||||||
session.SetToken(oauthStateString, enum.Github.String())
|
session.SetSocailLoginState(oauthStateString, enum.Github.String())
|
||||||
oauth.OAuthProvider.GithubConfig.RedirectURL = constants.AUTHORIZER_URL + "/oauth_callback/github"
|
oauth.OAuthProvider.GithubConfig.RedirectURL = constants.AUTHORIZER_URL + "/oauth_callback/github"
|
||||||
url := oauth.OAuthProvider.GithubConfig.AuthCodeURL(oauthStateString)
|
url := oauth.OAuthProvider.GithubConfig.AuthCodeURL(oauthStateString)
|
||||||
c.Redirect(http.StatusTemporaryRedirect, url)
|
c.Redirect(http.StatusTemporaryRedirect, url)
|
||||||
case enum.Facebook.String():
|
case enum.Facebook.String():
|
||||||
session.SetToken(oauthStateString, enum.Github.String())
|
session.SetSocailLoginState(oauthStateString, enum.Facebook.String())
|
||||||
oauth.OAuthProvider.FacebookConfig.RedirectURL = constants.AUTHORIZER_URL + "/oauth_callback/facebook"
|
oauth.OAuthProvider.FacebookConfig.RedirectURL = constants.AUTHORIZER_URL + "/oauth_callback/facebook"
|
||||||
url := oauth.OAuthProvider.FacebookConfig.AuthCodeURL(oauthStateString)
|
url := oauth.OAuthProvider.FacebookConfig.AuthCodeURL(oauthStateString)
|
||||||
c.Redirect(http.StatusTemporaryRedirect, url)
|
c.Redirect(http.StatusTemporaryRedirect, url)
|
||||||
|
|
|
@ -56,7 +56,16 @@ func VerifyEmailHandler() gin.HandlerFunc {
|
||||||
|
|
||||||
accessToken, _, _ := utils.CreateAuthToken(user, enum.AccessToken, roles)
|
accessToken, _, _ := utils.CreateAuthToken(user, enum.AccessToken, roles)
|
||||||
|
|
||||||
session.SetToken(userIdStr, refreshToken)
|
session.SetToken(userIdStr, accessToken, refreshToken)
|
||||||
|
go func() {
|
||||||
|
sessionData := db.Session{
|
||||||
|
UserID: user.ID,
|
||||||
|
UserAgent: utils.GetUserAgent(c.Request),
|
||||||
|
IP: utils.GetIP(c.Request),
|
||||||
|
}
|
||||||
|
|
||||||
|
db.Mgr.SaveSession(sessionData)
|
||||||
|
}()
|
||||||
utils.SetCookie(c, accessToken)
|
utils.SetCookie(c, accessToken)
|
||||||
c.Redirect(http.StatusTemporaryRedirect, claim.Host)
|
c.Redirect(http.StatusTemporaryRedirect, claim.Host)
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,7 +60,7 @@ func AdminUpdateUser(ctx context.Context, params model.AdminUpdateUserInput) (*m
|
||||||
return res, fmt.Errorf("user with this email address already exists")
|
return res, fmt.Errorf("user with this email address already exists")
|
||||||
}
|
}
|
||||||
|
|
||||||
session.DeleteToken(fmt.Sprintf("%v", user.ID))
|
session.DeleteUserSession(fmt.Sprintf("%v", user.ID))
|
||||||
utils.DeleteCookie(gc)
|
utils.DeleteCookie(gc)
|
||||||
|
|
||||||
user.Email = newEmail
|
user.Email = newEmail
|
||||||
|
@ -100,7 +100,7 @@ func AdminUpdateUser(ctx context.Context, params model.AdminUpdateUserInput) (*m
|
||||||
rolesToSave = strings.Join(inputRoles, ",")
|
rolesToSave = strings.Join(inputRoles, ",")
|
||||||
}
|
}
|
||||||
|
|
||||||
session.DeleteToken(fmt.Sprintf("%v", user.ID))
|
session.DeleteUserSession(fmt.Sprintf("%v", user.ID))
|
||||||
utils.DeleteCookie(gc)
|
utils.DeleteCookie(gc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ func DeleteUser(ctx context.Context, params model.DeleteUserInput) (*model.Respo
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
|
|
||||||
session.DeleteToken(fmt.Sprintf("%x", user.ID))
|
session.DeleteUserSession(fmt.Sprintf("%x", user.ID))
|
||||||
|
|
||||||
err = db.Mgr.DeleteUser(params.Email)
|
err = db.Mgr.DeleteUser(params.Email)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -60,7 +60,16 @@ func Login(ctx context.Context, params model.LoginInput) (*model.AuthResponse, e
|
||||||
|
|
||||||
accessToken, expiresAt, _ := utils.CreateAuthToken(user, enum.AccessToken, roles)
|
accessToken, expiresAt, _ := utils.CreateAuthToken(user, enum.AccessToken, roles)
|
||||||
|
|
||||||
session.SetToken(userIdStr, refreshToken)
|
session.SetToken(userIdStr, accessToken, refreshToken)
|
||||||
|
go func() {
|
||||||
|
sessionData := db.Session{
|
||||||
|
UserID: user.ID,
|
||||||
|
UserAgent: utils.GetUserAgent(gc.Request),
|
||||||
|
IP: utils.GetIP(gc.Request),
|
||||||
|
}
|
||||||
|
|
||||||
|
db.Mgr.SaveSession(sessionData)
|
||||||
|
}()
|
||||||
|
|
||||||
res = &model.AuthResponse{
|
res = &model.AuthResponse{
|
||||||
Message: `Logged in successfully`,
|
Message: `Logged in successfully`,
|
||||||
|
|
|
@ -27,7 +27,7 @@ func Logout(ctx context.Context) (*model.Response, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
userId := fmt.Sprintf("%v", claim["id"])
|
userId := fmt.Sprintf("%v", claim["id"])
|
||||||
session.DeleteToken(userId)
|
session.DeleteToken(userId, token)
|
||||||
res = &model.Response{
|
res = &model.Response{
|
||||||
Message: "Logged out successfully",
|
Message: "Logged out successfully",
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,7 @@ func Profile(ctx context.Context) (*model.User, error) {
|
||||||
|
|
||||||
userID := fmt.Sprintf("%v", claim["id"])
|
userID := fmt.Sprintf("%v", claim["id"])
|
||||||
email := fmt.Sprintf("%v", claim["email"])
|
email := fmt.Sprintf("%v", claim["email"])
|
||||||
sessionToken := session.GetToken(userID)
|
sessionToken := session.GetToken(userID, token)
|
||||||
|
|
||||||
if sessionToken == "" {
|
if sessionToken == "" {
|
||||||
return res, fmt.Errorf(`unauthorized`)
|
return res, fmt.Errorf(`unauthorized`)
|
||||||
|
|
|
@ -127,7 +127,16 @@ func Signup(ctx context.Context, params model.SignUpInput) (*model.AuthResponse,
|
||||||
|
|
||||||
accessToken, expiresAt, _ := utils.CreateAuthToken(user, enum.AccessToken, roles)
|
accessToken, expiresAt, _ := utils.CreateAuthToken(user, enum.AccessToken, roles)
|
||||||
|
|
||||||
session.SetToken(userIdStr, refreshToken)
|
session.SetToken(userIdStr, accessToken, refreshToken)
|
||||||
|
go func() {
|
||||||
|
sessionData := db.Session{
|
||||||
|
UserID: user.ID,
|
||||||
|
UserAgent: utils.GetUserAgent(gc.Request),
|
||||||
|
IP: utils.GetIP(gc.Request),
|
||||||
|
}
|
||||||
|
|
||||||
|
db.Mgr.SaveSession(sessionData)
|
||||||
|
}()
|
||||||
res = &model.AuthResponse{
|
res = &model.AuthResponse{
|
||||||
Message: `Signed up successfully.`,
|
Message: `Signed up successfully.`,
|
||||||
AccessToken: &accessToken,
|
AccessToken: &accessToken,
|
||||||
|
|
|
@ -37,7 +37,7 @@ func Token(ctx context.Context, roles []string) (*model.AuthResponse, error) {
|
||||||
|
|
||||||
userIdStr := fmt.Sprintf("%v", user.ID)
|
userIdStr := fmt.Sprintf("%v", user.ID)
|
||||||
|
|
||||||
sessionToken := session.GetToken(userIdStr)
|
sessionToken := session.GetToken(userIdStr, token)
|
||||||
|
|
||||||
if sessionToken == "" {
|
if sessionToken == "" {
|
||||||
return res, fmt.Errorf(`unauthorized`)
|
return res, fmt.Errorf(`unauthorized`)
|
||||||
|
@ -63,7 +63,19 @@ func Token(ctx context.Context, roles []string) (*model.AuthResponse, error) {
|
||||||
if accessTokenErr != nil || expiresTimeObj.Sub(currentTimeObj).Minutes() <= 5 {
|
if accessTokenErr != nil || expiresTimeObj.Sub(currentTimeObj).Minutes() <= 5 {
|
||||||
// if access token has expired and refresh/session token is valid
|
// if access token has expired and refresh/session token is valid
|
||||||
// generate new accessToken
|
// generate new accessToken
|
||||||
|
currentRefreshToken := session.GetToken(userIdStr, token)
|
||||||
|
session.DeleteToken(userIdStr, token)
|
||||||
token, expiresAt, _ = utils.CreateAuthToken(user, enum.AccessToken, claimRoles)
|
token, expiresAt, _ = utils.CreateAuthToken(user, enum.AccessToken, claimRoles)
|
||||||
|
session.SetToken(userIdStr, token, currentRefreshToken)
|
||||||
|
go func() {
|
||||||
|
sessionData := db.Session{
|
||||||
|
UserID: user.ID,
|
||||||
|
UserAgent: utils.GetUserAgent(gc.Request),
|
||||||
|
IP: utils.GetIP(gc.Request),
|
||||||
|
}
|
||||||
|
|
||||||
|
db.Mgr.SaveSession(sessionData)
|
||||||
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
utils.SetCookie(gc, token)
|
utils.SetCookie(gc, token)
|
||||||
|
|
|
@ -33,7 +33,7 @@ func UpdateProfile(ctx context.Context, params model.UpdateProfileInput) (*model
|
||||||
}
|
}
|
||||||
|
|
||||||
id := fmt.Sprintf("%v", claim["id"])
|
id := fmt.Sprintf("%v", claim["id"])
|
||||||
sessionToken := session.GetToken(id)
|
sessionToken := session.GetToken(id, token)
|
||||||
|
|
||||||
if sessionToken == "" {
|
if sessionToken == "" {
|
||||||
return res, fmt.Errorf(`unauthorized`)
|
return res, fmt.Errorf(`unauthorized`)
|
||||||
|
@ -99,7 +99,7 @@ func UpdateProfile(ctx context.Context, params model.UpdateProfileInput) (*model
|
||||||
return res, fmt.Errorf("user with this email address already exists")
|
return res, fmt.Errorf("user with this email address already exists")
|
||||||
}
|
}
|
||||||
|
|
||||||
session.DeleteToken(fmt.Sprintf("%v", user.ID))
|
session.DeleteUserSession(fmt.Sprintf("%v", user.ID))
|
||||||
utils.DeleteCookie(gc)
|
utils.DeleteCookie(gc)
|
||||||
|
|
||||||
user.Email = newEmail
|
user.Email = newEmail
|
||||||
|
|
|
@ -47,7 +47,16 @@ func VerifyEmail(ctx context.Context, params model.VerifyEmailInput) (*model.Aut
|
||||||
|
|
||||||
accessToken, expiresAt, _ := utils.CreateAuthToken(user, enum.AccessToken, roles)
|
accessToken, expiresAt, _ := utils.CreateAuthToken(user, enum.AccessToken, roles)
|
||||||
|
|
||||||
session.SetToken(userIdStr, refreshToken)
|
session.SetToken(userIdStr, accessToken, refreshToken)
|
||||||
|
go func() {
|
||||||
|
sessionData := db.Session{
|
||||||
|
UserID: user.ID,
|
||||||
|
UserAgent: utils.GetUserAgent(gc.Request),
|
||||||
|
IP: utils.GetIP(gc.Request),
|
||||||
|
}
|
||||||
|
|
||||||
|
db.Mgr.SaveSession(sessionData)
|
||||||
|
}()
|
||||||
|
|
||||||
res = &model.AuthResponse{
|
res = &model.AuthResponse{
|
||||||
Message: `Email verified successfully.`,
|
Message: `Email verified successfully.`,
|
||||||
|
|
|
@ -1,41 +1,88 @@
|
||||||
package session
|
package session
|
||||||
|
|
||||||
import "sync"
|
import (
|
||||||
|
"log"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
type InMemoryStore struct {
|
type InMemoryStore struct {
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
store map[string]string
|
store map[string]map[string]string
|
||||||
|
socialLoginState map[string]string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *InMemoryStore) AddToken(userId, token string) {
|
func (c *InMemoryStore) AddToken(userId, accessToken, refreshToken string) {
|
||||||
c.mu.Lock()
|
c.mu.Lock()
|
||||||
// delete sessions > 500 // not recommended for production
|
// delete sessions > 500 // not recommended for production
|
||||||
if len(c.store) >= 500 {
|
if len(c.store) >= 500 {
|
||||||
c.store = make(map[string]string)
|
c.store = map[string]map[string]string{}
|
||||||
}
|
}
|
||||||
c.store[userId] = token
|
// check if entry exists in map
|
||||||
|
_, exists := c.store[userId]
|
||||||
|
if exists {
|
||||||
|
tempMap := c.store[userId]
|
||||||
|
tempMap[accessToken] = refreshToken
|
||||||
|
c.store[userId] = tempMap
|
||||||
|
} else {
|
||||||
|
tempMap := map[string]string{
|
||||||
|
accessToken: refreshToken,
|
||||||
|
}
|
||||||
|
c.store[userId] = tempMap
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Println(c.store)
|
||||||
|
|
||||||
c.mu.Unlock()
|
c.mu.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *InMemoryStore) DeleteToken(userId string) {
|
func (c *InMemoryStore) DeleteUserSession(userId string) {
|
||||||
c.mu.Lock()
|
c.mu.Lock()
|
||||||
delete(c.store, userId)
|
delete(c.store, userId)
|
||||||
c.mu.Unlock()
|
c.mu.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *InMemoryStore) ClearStore() {
|
func (c *InMemoryStore) DeleteToken(userId, accessToken string) {
|
||||||
c.mu.Lock()
|
c.mu.Lock()
|
||||||
c.store = make(map[string]string)
|
delete(c.store[userId], accessToken)
|
||||||
c.mu.Unlock()
|
c.mu.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *InMemoryStore) GetToken(userId string) string {
|
func (c *InMemoryStore) ClearStore() {
|
||||||
|
c.mu.Lock()
|
||||||
|
c.store = map[string]map[string]string{}
|
||||||
|
c.mu.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *InMemoryStore) GetToken(userId, accessToken string) string {
|
||||||
token := ""
|
token := ""
|
||||||
c.mu.Lock()
|
c.mu.Lock()
|
||||||
if val, ok := c.store[userId]; ok {
|
if sessionMap, ok := c.store[userId]; ok {
|
||||||
token = val
|
if val, ok := sessionMap[accessToken]; ok {
|
||||||
|
token = val
|
||||||
|
}
|
||||||
}
|
}
|
||||||
c.mu.Unlock()
|
c.mu.Unlock()
|
||||||
|
|
||||||
return token
|
return token
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *InMemoryStore) SetSocialLoginState(key, state string) {
|
||||||
|
c.mu.Lock()
|
||||||
|
c.socialLoginState[key] = state
|
||||||
|
c.mu.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *InMemoryStore) GetSocialLoginState(key string) string {
|
||||||
|
state := ""
|
||||||
|
if stateVal, ok := c.socialLoginState[key]; ok {
|
||||||
|
state = stateVal
|
||||||
|
}
|
||||||
|
|
||||||
|
return state
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *InMemoryStore) RemoveSocialLoginState(key string) {
|
||||||
|
c.mu.Lock()
|
||||||
|
delete(c.socialLoginState, key)
|
||||||
|
c.mu.Unlock()
|
||||||
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package session
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
"github.com/go-redis/redis/v8"
|
"github.com/go-redis/redis/v8"
|
||||||
|
@ -12,20 +13,29 @@ type RedisStore struct {
|
||||||
store *redis.Client
|
store *redis.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *RedisStore) AddToken(userId, token string) {
|
func (c *RedisStore) AddToken(userId, accessToken, refreshToken string) {
|
||||||
err := c.store.Set(c.ctx, "authorizer_"+userId, token, 0).Err()
|
err := c.store.HMSet(c.ctx, "authorizer_"+userId, map[string]string{
|
||||||
|
accessToken: refreshToken,
|
||||||
|
}).Err()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalln("Error saving redis token:", err)
|
log.Fatalln("Error saving redis token:", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *RedisStore) DeleteToken(userId string) {
|
func (c *RedisStore) DeleteUserSession(userId string) {
|
||||||
err := c.store.Del(c.ctx, "authorizer_"+userId).Err()
|
err := c.store.Del(c.ctx, "authorizer_"+userId).Err()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalln("Error deleting redis token:", err)
|
log.Fatalln("Error deleting redis token:", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *RedisStore) DeleteToken(userId, accessToken string) {
|
||||||
|
err := c.store.HDel(c.ctx, "authorizer_"+userId, accessToken).Err()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln("Error deleting redis token:", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (c *RedisStore) ClearStore() {
|
func (c *RedisStore) ClearStore() {
|
||||||
err := c.store.Del(c.ctx, "authorizer_*").Err()
|
err := c.store.Del(c.ctx, "authorizer_*").Err()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -33,11 +43,38 @@ func (c *RedisStore) ClearStore() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *RedisStore) GetToken(userId string) string {
|
func (c *RedisStore) GetToken(userId, accessToken string) string {
|
||||||
token := ""
|
token := ""
|
||||||
token, err := c.store.Get(c.ctx, "authorizer_"+userId).Result()
|
res, err := c.store.HMGet(c.ctx, "authorizer_"+userId, accessToken).Result()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("Error getting token from redis store:", err)
|
log.Println("Error getting token from redis store:", err)
|
||||||
}
|
}
|
||||||
|
if len(res) > 0 && res[0] != nil {
|
||||||
|
token = fmt.Sprintf("%v", res[0])
|
||||||
|
}
|
||||||
return token
|
return token
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *RedisStore) SetSocialLoginState(key, state string) {
|
||||||
|
err := c.store.Set(c.ctx, key, state, 0).Err()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln("Error saving redis token:", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *RedisStore) GetSocialLoginState(key string) string {
|
||||||
|
state := ""
|
||||||
|
state, err := c.store.Get(c.ctx, key).Result()
|
||||||
|
if err != nil {
|
||||||
|
log.Println("Error getting token from redis store:", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return state
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *RedisStore) RemoveSocialLoginState(key string) {
|
||||||
|
err := c.store.Del(c.ctx, key).Err()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln("Error deleting redis token:", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -15,30 +15,42 @@ type SessionStore struct {
|
||||||
|
|
||||||
var SessionStoreObj SessionStore
|
var SessionStoreObj SessionStore
|
||||||
|
|
||||||
func SetToken(userId, token string) {
|
func SetToken(userId, accessToken, refreshToken string) {
|
||||||
|
// TODO: Set session information in db for all the sessions that gets generated
|
||||||
|
// it should async go function
|
||||||
|
|
||||||
if SessionStoreObj.RedisMemoryStoreObj != nil {
|
if SessionStoreObj.RedisMemoryStoreObj != nil {
|
||||||
SessionStoreObj.RedisMemoryStoreObj.AddToken(userId, token)
|
SessionStoreObj.RedisMemoryStoreObj.AddToken(userId, accessToken, refreshToken)
|
||||||
}
|
}
|
||||||
if SessionStoreObj.InMemoryStoreObj != nil {
|
if SessionStoreObj.InMemoryStoreObj != nil {
|
||||||
SessionStoreObj.InMemoryStoreObj.AddToken(userId, token)
|
SessionStoreObj.InMemoryStoreObj.AddToken(userId, accessToken, refreshToken)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func DeleteToken(userId string) {
|
func DeleteToken(userId, accessToken string) {
|
||||||
if SessionStoreObj.RedisMemoryStoreObj != nil {
|
if SessionStoreObj.RedisMemoryStoreObj != nil {
|
||||||
SessionStoreObj.RedisMemoryStoreObj.DeleteToken(userId)
|
SessionStoreObj.RedisMemoryStoreObj.DeleteToken(userId, accessToken)
|
||||||
}
|
}
|
||||||
if SessionStoreObj.InMemoryStoreObj != nil {
|
if SessionStoreObj.InMemoryStoreObj != nil {
|
||||||
SessionStoreObj.InMemoryStoreObj.DeleteToken(userId)
|
SessionStoreObj.InMemoryStoreObj.DeleteToken(userId, accessToken)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetToken(userId string) string {
|
func DeleteUserSession(userId string) {
|
||||||
if SessionStoreObj.RedisMemoryStoreObj != nil {
|
if SessionStoreObj.RedisMemoryStoreObj != nil {
|
||||||
return SessionStoreObj.RedisMemoryStoreObj.GetToken(userId)
|
SessionStoreObj.RedisMemoryStoreObj.DeleteUserSession(userId)
|
||||||
}
|
}
|
||||||
if SessionStoreObj.InMemoryStoreObj != nil {
|
if SessionStoreObj.InMemoryStoreObj != nil {
|
||||||
return SessionStoreObj.InMemoryStoreObj.GetToken(userId)
|
SessionStoreObj.InMemoryStoreObj.DeleteUserSession(userId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetToken(userId, accessToken string) string {
|
||||||
|
if SessionStoreObj.RedisMemoryStoreObj != nil {
|
||||||
|
return SessionStoreObj.RedisMemoryStoreObj.GetToken(userId, accessToken)
|
||||||
|
}
|
||||||
|
if SessionStoreObj.InMemoryStoreObj != nil {
|
||||||
|
return SessionStoreObj.InMemoryStoreObj.GetToken(userId, accessToken)
|
||||||
}
|
}
|
||||||
|
|
||||||
return ""
|
return ""
|
||||||
|
@ -53,6 +65,35 @@ func ClearStore() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func SetSocailLoginState(key, state string) {
|
||||||
|
if SessionStoreObj.RedisMemoryStoreObj != nil {
|
||||||
|
SessionStoreObj.RedisMemoryStoreObj.SetSocialLoginState(key, state)
|
||||||
|
}
|
||||||
|
if SessionStoreObj.InMemoryStoreObj != nil {
|
||||||
|
SessionStoreObj.InMemoryStoreObj.SetSocialLoginState(key, state)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetSocailLoginState(key string) string {
|
||||||
|
if SessionStoreObj.RedisMemoryStoreObj != nil {
|
||||||
|
return SessionStoreObj.RedisMemoryStoreObj.GetSocialLoginState(key)
|
||||||
|
}
|
||||||
|
if SessionStoreObj.InMemoryStoreObj != nil {
|
||||||
|
return SessionStoreObj.InMemoryStoreObj.GetSocialLoginState(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func RemoveSocialLoginState(key string) {
|
||||||
|
if SessionStoreObj.RedisMemoryStoreObj != nil {
|
||||||
|
SessionStoreObj.RedisMemoryStoreObj.RemoveSocialLoginState(key)
|
||||||
|
}
|
||||||
|
if SessionStoreObj.InMemoryStoreObj != nil {
|
||||||
|
SessionStoreObj.InMemoryStoreObj.RemoveSocialLoginState(key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func InitSession() {
|
func InitSession() {
|
||||||
if constants.REDIS_URL != "" {
|
if constants.REDIS_URL != "" {
|
||||||
log.Println("Using redis store to save sessions")
|
log.Println("Using redis store to save sessions")
|
||||||
|
@ -75,7 +116,8 @@ func InitSession() {
|
||||||
} else {
|
} else {
|
||||||
log.Println("Using in memory store to save sessions")
|
log.Println("Using in memory store to save sessions")
|
||||||
SessionStoreObj.InMemoryStoreObj = &InMemoryStore{
|
SessionStoreObj.InMemoryStoreObj = &InMemoryStore{
|
||||||
store: make(map[string]string),
|
store: map[string]map[string]string{},
|
||||||
|
socialLoginState: map[string]string{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
19
server/utils/requestInfo.go
Normal file
19
server/utils/requestInfo.go
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
package utils
|
||||||
|
|
||||||
|
import "net/http"
|
||||||
|
|
||||||
|
func GetIP(r *http.Request) string {
|
||||||
|
IPAddress := r.Header.Get("X-Real-Ip")
|
||||||
|
if IPAddress == "" {
|
||||||
|
IPAddress = r.Header.Get("X-Forwarded-For")
|
||||||
|
}
|
||||||
|
|
||||||
|
if IPAddress == "" {
|
||||||
|
IPAddress = r.RemoteAddr
|
||||||
|
}
|
||||||
|
return IPAddress
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetUserAgent(r *http.Request) string {
|
||||||
|
return r.UserAgent()
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user