cup/hooks/auth-check.go

96 lines
2.8 KiB
Go

package hooks
import (
"errors"
"net/http"
"strings"
"git.smarteching.com/goffee/core"
"git.smarteching.com/goffee/cup/models"
"gorm.io/gorm"
)
var CheckSessionCookie core.Hook = func(c *core.Context) {
pass := false
// Validate the cookie based session through the core session. This also
// transparently performs sliding expiration renewal when applicable.
session := c.GetSession()
if session.Init(c) {
// ensure the authenticated user still exists in the database
var user models.User
res := c.GetGorm().Where("id = ?", session.GetUserID()).First(&user)
if res.Error == nil {
pass = true
} else if errors.Is(res.Error, gorm.ErrRecordNotFound) {
// the user no longer exists: invalidate the session and remove the
// now-useless cookie so the client does not keep sending it.
_ = c.GetCache().Delete(core.CreateAuthTokenHashedCacheKey(session.GetUserID(), c.GetUserAgent()))
_ = core.ClearCookie(c.Response.HttpResponseWriter)
} else {
// database error: log it; the session is not validated.
c.GetLogger().Error(res.Error.Error())
_ = core.ClearCookie(c.Response.HttpResponseWriter)
}
}
if pass {
c.Next()
} else {
c.Response.Redirect("/applogin").ForceSendResponse()
return
}
}
var APIAuthCheck core.Hook = func(c *core.Context) {
// --- API/bearer flow ---
tokenRaw := c.GetHeader("Authorization")
token := strings.TrimSpace(strings.Replace(tokenRaw, "Bearer", "", 1))
if token == "" {
c.Response.SetStatusCode(http.StatusUnauthorized).Json(c.MapToJson(map[string]interface{}{
"message": "unauthorized",
})).ForceSendResponse()
return
}
payload, err := c.GetJWT().DecodeToken(token)
if err != nil {
c.Response.SetStatusCode(http.StatusUnauthorized).Json(c.MapToJson(map[string]interface{}{
"message": "unauthorized",
})).ForceSendResponse()
return
}
userAgent := c.GetUserAgent()
hashedCacheKey := core.CreateAuthTokenHashedCacheKey(uint(c.CastToInt(payload["userID"])), userAgent)
cachedToken, err := c.GetCache().Get(hashedCacheKey)
if err != nil {
// user signed out
c.Response.SetStatusCode(http.StatusUnauthorized).Json(c.MapToJson(map[string]interface{}{
"message": "unauthorized",
})).ForceSendResponse()
return
}
if cachedToken != token {
// using old token replaced with new one after recent signin
c.Response.SetStatusCode(http.StatusUnauthorized).Json(c.MapToJson(map[string]interface{}{
"message": "unauthorized",
})).ForceSendResponse()
return
}
var user models.User
res := c.GetGorm().Where("id = ?", payload["userID"]).First(&user)
if res.Error != nil && !errors.Is(res.Error, gorm.ErrRecordNotFound) {
// error with the database
c.GetLogger().Error(res.Error.Error())
c.Response.SetStatusCode(http.StatusInternalServerError).Json(c.MapToJson(map[string]interface{}{
"message": "internal error",
})).ForceSendResponse()
return
}
c.Next()
}