Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: [#547] Auth supports session driver #820

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
153 changes: 153 additions & 0 deletions auth/auth_session.go
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

File name: auth_session.go -> session.go

Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
package auth

import (
"fmt"
"time"

"github.com/spf13/cast"
"gorm.io/gorm/clause"

contractsauth "github.com/goravel/framework/contracts/auth"
"github.com/goravel/framework/contracts/cache"
"github.com/goravel/framework/contracts/config"
"github.com/goravel/framework/contracts/database/orm"
"github.com/goravel/framework/contracts/http"
"github.com/goravel/framework/errors"
"github.com/goravel/framework/support/database"
)

const sessionCtxKey = "GoravelSessionAuth"

type Session struct {
SessionID string
}

type Sessions map[string]*Session

type SessionAuth struct {
cache cache.Cache
config config.Config
ctx http.Context
session string
orm orm.Orm
}

func NewSessionAuth(session string, cache cache.Cache, config config.Config, ctx http.Context, orm orm.Orm) *SessionAuth {
return &SessionAuth{
cache: cache,
config: config,
ctx: ctx,
session: session,
orm: orm,
}

Check warning on line 42 in auth/auth_session.go

View check run for this annotation

Codecov / codecov/patch

auth/auth_session.go#L35-L42

Added lines #L35 - L42 were not covered by tests
}

func (a *SessionAuth) Session(name string) contractsauth.Auth {
return NewAuth(name, a.cache, a.config, a.ctx, a.orm)

Check warning on line 46 in auth/auth_session.go

View check run for this annotation

Codecov / codecov/patch

auth/auth_session.go#L45-L46

Added lines #L45 - L46 were not covered by tests
}

func (a *SessionAuth) SessionUser(user any) error {
auth, ok := a.ctx.Value(sessionCtxKey).(Sessions)
if !ok || auth[a.session] == nil {
return errors.AuthParseTokenFirst
}
if auth[a.session].SessionID == "" {
return errors.AuthInvalidKey
}

Check warning on line 56 in auth/auth_session.go

View check run for this annotation

Codecov / codecov/patch

auth/auth_session.go#L49-L56

Added lines #L49 - L56 were not covered by tests

if err := a.orm.Query().FindOrFail(user, clause.Eq{Column: clause.PrimaryColumn, Value: auth[a.session].SessionID}); err != nil {
return err
}

Check warning on line 60 in auth/auth_session.go

View check run for this annotation

Codecov / codecov/patch

auth/auth_session.go#L58-L60

Added lines #L58 - L60 were not covered by tests

return nil

Check warning on line 62 in auth/auth_session.go

View check run for this annotation

Codecov / codecov/patch

auth/auth_session.go#L62

Added line #L62 was not covered by tests
}

func (a *SessionAuth) SessionID() (string, error) {
auth, ok := a.ctx.Value(sessionCtxKey).(Sessions)
if !ok || auth[a.session] == nil {
return "", errors.AuthParseTokenFirst
}
if auth[a.session].SessionID == "" {
return "", errors.AuthInvalidKey
}

Check warning on line 72 in auth/auth_session.go

View check run for this annotation

Codecov / codecov/patch

auth/auth_session.go#L65-L72

Added lines #L65 - L72 were not covered by tests

return auth[a.session].SessionID, nil

Check warning on line 74 in auth/auth_session.go

View check run for this annotation

Codecov / codecov/patch

auth/auth_session.go#L74

Added line #L74 was not covered by tests
}

func (a *SessionAuth) SessionLogin(user any) (string, error) {
id := database.GetID(user)
if id == nil {
return "", errors.AuthNoPrimaryKeyField
}

Check warning on line 81 in auth/auth_session.go

View check run for this annotation

Codecov / codecov/patch

auth/auth_session.go#L77-L81

Added lines #L77 - L81 were not covered by tests

sessionID := cast.ToString(id)
if sessionID == "" {
return "", errors.AuthInvalidKey
}

Check warning on line 86 in auth/auth_session.go

View check run for this annotation

Codecov / codecov/patch

auth/auth_session.go#L83-L86

Added lines #L83 - L86 were not covered by tests

if err := a.cache.Put(getSessionCacheKey(sessionID), true, time.Duration(a.getSessionTtl())*time.Minute); err != nil {
return "", err
}

Check warning on line 90 in auth/auth_session.go

View check run for this annotation

Codecov / codecov/patch

auth/auth_session.go#L88-L90

Added lines #L88 - L90 were not covered by tests

a.makeSessionAuthContext(sessionID)

return sessionID, nil

Check warning on line 94 in auth/auth_session.go

View check run for this annotation

Codecov / codecov/patch

auth/auth_session.go#L92-L94

Added lines #L92 - L94 were not covered by tests
}

func (a *SessionAuth) SessionLogout() error {
auth, ok := a.ctx.Value(sessionCtxKey).(Sessions)
if !ok || auth[a.session] == nil || auth[a.session].SessionID == "" {
return nil
}

Check warning on line 101 in auth/auth_session.go

View check run for this annotation

Codecov / codecov/patch

auth/auth_session.go#L97-L101

Added lines #L97 - L101 were not covered by tests

if err := a.cache.Put(getSessionCacheKey(auth[a.session].SessionID), true, time.Duration(a.getSessionTtl())*time.Minute); err != nil {
return err
}

Check warning on line 105 in auth/auth_session.go

View check run for this annotation

Codecov / codecov/patch

auth/auth_session.go#L103-L105

Added lines #L103 - L105 were not covered by tests

delete(auth, a.session)
a.ctx.WithValue(sessionCtxKey, auth)

return nil

Check warning on line 110 in auth/auth_session.go

View check run for this annotation

Codecov / codecov/patch

auth/auth_session.go#L107-L110

Added lines #L107 - L110 were not covered by tests
}

func (a *SessionAuth) SessionRefresh() (string, error) {
auth, ok := a.ctx.Value(sessionCtxKey).(Sessions)
if !ok || auth[a.session] == nil {
return "", errors.AuthParseTokenFirst
}

Check warning on line 117 in auth/auth_session.go

View check run for this annotation

Codecov / codecov/patch

auth/auth_session.go#L113-L117

Added lines #L113 - L117 were not covered by tests

if !a.cache.GetBool(getSessionCacheKey(auth[a.session].SessionID), false) {
return "", errors.AuthTokenExpired
}

Check warning on line 121 in auth/auth_session.go

View check run for this annotation

Codecov / codecov/patch

auth/auth_session.go#L119-L121

Added lines #L119 - L121 were not covered by tests

return auth[a.session].SessionID, nil

Check warning on line 123 in auth/auth_session.go

View check run for this annotation

Codecov / codecov/patch

auth/auth_session.go#L123

Added line #L123 was not covered by tests
}

func (a *SessionAuth) makeSessionAuthContext(sessionID string) {
sessions, ok := a.ctx.Value(sessionCtxKey).(Sessions)
if !ok {
sessions = make(Sessions)
}
sessions[a.session] = &Session{SessionID: sessionID}
a.ctx.WithValue(sessionCtxKey, sessions)

Check warning on line 132 in auth/auth_session.go

View check run for this annotation

Codecov / codecov/patch

auth/auth_session.go#L126-L132

Added lines #L126 - L132 were not covered by tests
}

func (a *SessionAuth) getSessionTtl() int {
var ttl int
SessionTtl := a.config.Get(fmt.Sprintf("auth.Sessions.%s.ttl", a.session))
if SessionTtl == nil {
ttl = a.config.GetInt("session.ttl")
} else {
ttl = cast.ToInt(SessionTtl)
}

Check warning on line 142 in auth/auth_session.go

View check run for this annotation

Codecov / codecov/patch

auth/auth_session.go#L135-L142

Added lines #L135 - L142 were not covered by tests

if ttl == 0 {
ttl = 60 * 24 * 30
}

Check warning on line 146 in auth/auth_session.go

View check run for this annotation

Codecov / codecov/patch

auth/auth_session.go#L144-L146

Added lines #L144 - L146 were not covered by tests

return ttl

Check warning on line 148 in auth/auth_session.go

View check run for this annotation

Codecov / codecov/patch

auth/auth_session.go#L148

Added line #L148 was not covered by tests
}

func getSessionCacheKey(sessionID string) string {
return "session:" + sessionID

Check warning on line 152 in auth/auth_session.go

View check run for this annotation

Codecov / codecov/patch

auth/auth_session.go#L151-L152

Added lines #L151 - L152 were not covered by tests
}
64 changes: 64 additions & 0 deletions auth/jwt_driver.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package auth

import (
"errors"
"github.com/goravel/framework/contracts/cache"
"github.com/goravel/framework/contracts/config"
"github.com/goravel/framework/contracts/database/orm"
"github.com/goravel/framework/contracts/http"
)

type JWTDriver struct {
auth *Auth
}

func NewJWTDriver(config config.Config, cache cache.Cache, ctx http.Context, orm orm.Orm) *JWTDriver {
return &JWTDriver{
auth: NewAuth("jwt", cache, config, ctx, orm),
}

Check warning on line 18 in auth/jwt_driver.go

View check run for this annotation

Codecov / codecov/patch

auth/jwt_driver.go#L15-L18

Added lines #L15 - L18 were not covered by tests
}

func (d *JWTDriver) Login(userID string, data map[string]interface{}) (string, error) {
if userID == "" {
return "", errors.New("user ID is required")
}

Check warning on line 24 in auth/jwt_driver.go

View check run for this annotation

Codecov / codecov/patch

auth/jwt_driver.go#L21-L24

Added lines #L21 - L24 were not covered by tests

token, err := d.auth.LoginUsingID(userID)
if err != nil {
return "", err
}

Check warning on line 29 in auth/jwt_driver.go

View check run for this annotation

Codecov / codecov/patch

auth/jwt_driver.go#L26-L29

Added lines #L26 - L29 were not covered by tests

return token, nil

Check warning on line 31 in auth/jwt_driver.go

View check run for this annotation

Codecov / codecov/patch

auth/jwt_driver.go#L31

Added line #L31 was not covered by tests
}

func (d *JWTDriver) Logout(sessionID string) error {
if sessionID == "" {
return errors.New("session ID is required")
}

Check warning on line 37 in auth/jwt_driver.go

View check run for this annotation

Codecov / codecov/patch

auth/jwt_driver.go#L34-L37

Added lines #L34 - L37 were not covered by tests

d.auth.ctx.WithValue(ctxKey, Guards{
"jwt": &Guard{
Token: sessionID,
},
})

err := d.auth.Logout()
if err != nil {
return err
}

Check warning on line 48 in auth/jwt_driver.go

View check run for this annotation

Codecov / codecov/patch

auth/jwt_driver.go#L39-L48

Added lines #L39 - L48 were not covered by tests

return nil

Check warning on line 50 in auth/jwt_driver.go

View check run for this annotation

Codecov / codecov/patch

auth/jwt_driver.go#L50

Added line #L50 was not covered by tests
}

func (d *JWTDriver) Authenticate(sessionID string) error {
if sessionID == "" {
return errors.New("session ID is required")
}

Check warning on line 56 in auth/jwt_driver.go

View check run for this annotation

Codecov / codecov/patch

auth/jwt_driver.go#L53-L56

Added lines #L53 - L56 were not covered by tests

_, err := d.auth.Parse(sessionID)
if err != nil {
return err
}

Check warning on line 61 in auth/jwt_driver.go

View check run for this annotation

Codecov / codecov/patch

auth/jwt_driver.go#L58-L61

Added lines #L58 - L61 were not covered by tests

return nil

Check warning on line 63 in auth/jwt_driver.go

View check run for this annotation

Codecov / codecov/patch

auth/jwt_driver.go#L63

Added line #L63 was not covered by tests
}
7 changes: 7 additions & 0 deletions contracts/auth/driver.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package auth

type Driver interface {
Login(userID string, data map[string]interface{}) (string, error) // User login
Logout(sessionID string) error // User logout
Authenticate(sessionID string) error // Check authentication
}
Loading