1
0
mirror of https://github.com/volatiletech/authboss.git synced 2024-11-24 08:42:17 +02:00
authboss/context.go
Aaron L 24fc6196c7 Introduce new type of client storage
- This addresses the problem of having to update multiple times during
  one request. It's hard to have a nice interface especially with JWT
  because you always end up having to decode the request, encode new
  response, write header, then a second write to it comes, and where do
  you grab the value from? Often you don't have access to the response
  as a "read" structure. So we store it as events instead, and play
  those events against the original data right before the response is
  written to set the headers.
2017-02-24 16:45:47 -08:00

169 lines
3.9 KiB
Go

package authboss
import (
"context"
"net/http"
)
type contextKey string
const (
ctxKeyPID contextKey = "pid"
ctxKeyUser contextKey = "user"
ctxKeySessionState contextKey = "session"
ctxKeyCookieState contextKey = "cookie"
)
func (c contextKey) String() string {
return "authboss ctx key " + string(c)
}
// CurrentUserID retrieves the current user from the session.
func (a *Authboss) CurrentUserID(w http.ResponseWriter, r *http.Request) (string, error) {
if pid := r.Context().Value(ctxKeyPID); pid != nil {
return pid.(string), nil
}
_, err := a.Callbacks.FireBefore(EventGetUserSession, r.Context())
if err != nil {
return "", err
}
pid, _ := GetSession(r, SessionKey)
return pid, nil
}
// CurrentUserIDP retrieves the current user but panics if it's not available for
// any reason.
func (a *Authboss) CurrentUserIDP(w http.ResponseWriter, r *http.Request) string {
i, err := a.CurrentUserID(w, r)
if err != nil {
panic(err)
} else if len(i) == 0 {
panic(ErrUserNotFound)
}
return i
}
// CurrentUser retrieves the current user from the session and the database.
func (a *Authboss) CurrentUser(w http.ResponseWriter, r *http.Request) (Storer, error) {
if user := r.Context().Value(ctxKeyUser); user != nil {
return user.(Storer), nil
}
pid, err := a.CurrentUserID(w, r)
if err != nil {
return nil, err
} else if len(pid) == 0 {
return nil, nil
}
return a.currentUser(r.Context(), pid)
}
// CurrentUserP retrieves the current user but panics if it's not available for
// any reason.
func (a *Authboss) CurrentUserP(w http.ResponseWriter, r *http.Request) Storer {
i, err := a.CurrentUser(w, r)
if err != nil {
panic(err)
}
return i
}
func (a *Authboss) currentUser(ctx context.Context, pid string) (Storer, error) {
_, err := a.Callbacks.FireBefore(EventGetUser, ctx)
if err != nil {
return nil, err
}
user, err := a.StoreLoader.Load(ctx, pid)
if err != nil {
return nil, err
}
ctx = context.WithValue(ctx, ctxKeyUser, user)
err = a.Callbacks.FireAfter(EventGetUser, ctx)
if err != nil {
return nil, err
}
return user, nil
}
// LoadCurrentUser takes a pointer to a pointer to the request in order to
// change the current method's request pointer itself to the new request that
// contains the new context that has the pid in it.
func (a *Authboss) LoadCurrentUserID(w http.ResponseWriter, r **http.Request) (string, error) {
if pid := (*r).Context().Value(ctxKeyPID); pid != nil {
return pid.(string), nil
}
pid, err := a.CurrentUserID(w, *r)
if err != nil {
return "", err
}
if len(pid) == 0 {
return "", nil
}
ctx := context.WithValue((**r).Context(), ctxKeyPID, pid)
*r = (**r).WithContext(ctx)
return pid, nil
}
func (a *Authboss) LoadCurrentUserIDP(w http.ResponseWriter, r **http.Request) string {
pid, err := a.LoadCurrentUserID(w, r)
if err != nil {
panic(err)
} else if len(pid) == 0 {
panic(ErrUserNotFound)
}
return pid
}
// LoadCurrentUser takes a pointer to a pointer to the request in order to
// change the current method's request pointer itself to the new request that
// contains the new context that has the user in it. Calls LoadCurrentUserID
// so the primary id is also put in the context.
func (a *Authboss) LoadCurrentUser(w http.ResponseWriter, r **http.Request) (Storer, error) {
if user := (*r).Context().Value(ctxKeyUser); user != nil {
return user.(Storer), nil
}
pid, err := a.LoadCurrentUserID(w, r)
if err != nil {
return nil, err
}
if len(pid) == 0 {
return nil, nil
}
ctx := (**r).Context()
user, err := a.currentUser(ctx, pid)
if err != nil {
return nil, err
}
ctx = context.WithValue(ctx, ctxKeyUser, user)
*r = (**r).WithContext(ctx)
return user, nil
}
func (a *Authboss) LoadCurrentUserP(w http.ResponseWriter, r **http.Request) Storer {
user, err := a.LoadCurrentUser(w, r)
if err != nil {
panic(err)
} else if user == nil {
panic(ErrUserNotFound)
}
return user
}