264 lines
7.1 KiB
Go
264 lines
7.1 KiB
Go
package auth
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"log"
|
|
"net/http"
|
|
"time"
|
|
|
|
"github.com/golang-jwt/jwt/v5"
|
|
"github.com/jmoiron/sqlx"
|
|
"sismedika.com/sas/westone/configs"
|
|
"sismedika.com/sas/westone/types"
|
|
"sismedika.com/sas/westone/utils"
|
|
)
|
|
|
|
type ContextKey string
|
|
|
|
const UserContextKey ContextKey = "mk1S2sKM12KASd02dp1"
|
|
|
|
// func WithJWTAuth(handlerFunc http.HandlerFunc, store types.UserStore) http.HandlerFunc {
|
|
// return func(w http.ResponseWriter, r *http.Request) {
|
|
// tokenString := utils.GetTokenFromRequest(r)
|
|
// token, err := validateJWT(tokenString)
|
|
// if err != nil {
|
|
// log.Printf("failed to validate token: %v", err)
|
|
// permissionDenied(w)
|
|
// return
|
|
// }
|
|
|
|
// if !token.Valid {
|
|
// log.Println("invalid token")
|
|
// permissionDenied(w)
|
|
// return
|
|
// }
|
|
|
|
// claims := token.Claims.(jwt.MapClaims)
|
|
// str := claims["userID"].(string)
|
|
|
|
// userID, err := strconv.Atoi(str)
|
|
// if err != nil {
|
|
// log.Printf("failed to convert userID to int: %v", err)
|
|
// permissionDenied(w)
|
|
// return
|
|
// }
|
|
|
|
// u, err := store.GetUserByID(userID)
|
|
// if err != nil {
|
|
// log.Printf("failed to get user by id: %v", err)
|
|
// permissionDenied(w)
|
|
// return
|
|
// }
|
|
|
|
// // Add the user to the context
|
|
// ctx := r.Context()
|
|
// ctx = context.WithValue(ctx, UserKey, u.MUserID)
|
|
// r = r.WithContext(ctx)
|
|
|
|
// // Call the function if the token is valid
|
|
// handlerFunc(w, r)
|
|
// }
|
|
// }
|
|
|
|
func CreateJWT(data types.DataJWT) (string, error) {
|
|
secret := []byte(configs.Envs.JWTSecret)
|
|
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
|
|
"M_UserID": data.M_UserID,
|
|
"M_UserEmail": data.M_UserEmail,
|
|
"M_UserName": data.M_UserName,
|
|
"M_UserGroupDashboard": data.M_UserGroupDashboard,
|
|
"M_UserDefaultTSampleStationID": data.M_UserDefaultTSampleStationID,
|
|
"M_StaffName": data.M_StaffName,
|
|
"Is_Courier": data.Is_Courier,
|
|
"Time_Autologout": data.Time_Autologout,
|
|
"Type_Akun": data.Type_Akun,
|
|
"IP": data.Ip,
|
|
"Agent": data.Agent,
|
|
"Version": data.Version,
|
|
"LastLogin": data.LastLogin,
|
|
})
|
|
|
|
tokenString, err := token.SignedString(secret)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
return tokenString, err
|
|
}
|
|
|
|
func validateJWT(tokenString string) (*jwt.Token, error) {
|
|
return jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
|
|
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
|
|
err := fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
|
|
fmt.Printf("Error validating JWT token: %v\n", err)
|
|
return nil, err
|
|
}
|
|
|
|
return []byte(configs.Envs.JWTSecret), nil
|
|
})
|
|
}
|
|
|
|
func permissionDenied(w http.ResponseWriter) {
|
|
utils.WriteError(w, http.StatusForbidden, fmt.Errorf("PERMISSION DENIED"))
|
|
}
|
|
func tokenExpired(w http.ResponseWriter) {
|
|
utils.WriteError(w, http.StatusForbidden, fmt.Errorf("TOKEN EXPIRED"))
|
|
}
|
|
|
|
func GetUserIDFromContext(ctx context.Context) int {
|
|
userID, ok := ctx.Value(UserContextKey).(int)
|
|
if !ok {
|
|
return -1
|
|
}
|
|
|
|
return userID
|
|
}
|
|
|
|
func AuthMiddleware(next http.Handler) http.Handler {
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
tokenstr := utils.GetTokenFromRequest(r)
|
|
token, err := validateJWT(tokenstr)
|
|
if err != nil {
|
|
log.Printf("[ERROR] Failed to validate jwt token: %v", err)
|
|
permissionDenied(w)
|
|
return
|
|
}
|
|
|
|
if !token.Valid {
|
|
log.Println("[ERROR] Invalid token")
|
|
permissionDenied(w)
|
|
return
|
|
}
|
|
|
|
claims := token.Claims.(jwt.MapClaims)
|
|
ctx := r.Context()
|
|
ctx = context.WithValue(ctx, UserContextKey, claims)
|
|
r = r.WithContext(ctx)
|
|
|
|
next.ServeHTTP(w, r)
|
|
})
|
|
}
|
|
func WithAuthStore(store types.OauthStore) func(http.Handler) http.Handler {
|
|
return func(next http.Handler) http.Handler {
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
ctx := context.WithValue(r.Context(), "auth_store", store)
|
|
|
|
//start
|
|
tokenstr := utils.GetTokenFromRequest(r)
|
|
token, err := validateJWT(tokenstr)
|
|
if err != nil {
|
|
log.Printf("[ERROR] Failed to validate jwt token: %v", err)
|
|
permissionDenied(w)
|
|
return
|
|
}
|
|
|
|
if !token.Valid {
|
|
log.Println("[ERROR] Invalid token")
|
|
permissionDenied(w)
|
|
return
|
|
}
|
|
|
|
// claims := token.Claims.(jwt.MapClaims)
|
|
// userID := int(claims["M_UserID"].(float64))
|
|
|
|
// Ambil store dari context
|
|
// fmt.Printf("store: %v", store)
|
|
// store, ok := r.Context().Value("auth_store").(types.OauthStore)
|
|
// if !ok {
|
|
// log.Println("[ERROR] Auth store not found in context")
|
|
// permissionDenied(w)
|
|
// return
|
|
// }
|
|
|
|
// Update expired token
|
|
if err := store.UpdateExpiredToken(tokenstr); err != nil {
|
|
if err.Error() == "token expired" {
|
|
tokenExpired(w)
|
|
} else {
|
|
log.Printf("[ERROR] Failed to update token expiry: %v", err)
|
|
permissionDenied(w)
|
|
}
|
|
return
|
|
}
|
|
|
|
//end
|
|
next.ServeHTTP(w, r.WithContext(ctx))
|
|
})
|
|
}
|
|
}
|
|
|
|
func UpdateExpiredTokentest(userID int, db *sqlx.DB) error {
|
|
tx, err := db.BeginTxx(context.Background(), nil)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to begin transaction: %v", err)
|
|
}
|
|
|
|
defer func() {
|
|
if err != nil {
|
|
tx.Rollback()
|
|
}
|
|
}()
|
|
|
|
qrySys := `SELECT Conf_SystemIsAutoLogOut, Conf_SystemAutoLogOutDuration FROM conf_system LIMIT 1`
|
|
var isAutoLogOut string
|
|
var autoLogOutDuration int
|
|
err = db.QueryRow(qrySys).Scan(&isAutoLogOut, &autoLogOutDuration)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to get system config: %v", err)
|
|
}
|
|
|
|
if isAutoLogOut == "Y" {
|
|
qryEt := `SELECT DATE_FORMAT(M_UserExpiredToken, '%Y-%m-%d %H:%i:%s') as M_UserExpiredToken FROM m_user WHERE M_UserID = ?`
|
|
|
|
var expiredToken string
|
|
err = db.Get(&expiredToken, qryEt, userID)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to get expired token: %v", err)
|
|
}
|
|
|
|
timeNow := time.Now()
|
|
expiredTime, err := time.Parse("2006-01-02 15:04:05", expiredToken)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to parse expired token: %v", err)
|
|
}
|
|
|
|
if timeNow.After(expiredTime) {
|
|
return fmt.Errorf("token expired")
|
|
}
|
|
|
|
timeNowAdd := timeNow.Add(time.Duration(autoLogOutDuration) * time.Minute)
|
|
qryUpdateExpiredToken := `UPDATE m_user SET M_UserExpiredToken = ? WHERE M_UserID = ?`
|
|
_, err = tx.Exec(qryUpdateExpiredToken, timeNowAdd.Format("2006-01-02 15:04:05"), userID)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to update expired token: %v", err)
|
|
}
|
|
|
|
qry := `UPDATE m_user SET M_UserExpiredToken = NOW() WHERE M_UserID = :userID`
|
|
|
|
_, err = tx.NamedExec(qry, map[string]interface{}{
|
|
"userID": userID,
|
|
})
|
|
fmt.Println("err", err)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to update expired token: %v", err)
|
|
}
|
|
|
|
if err = tx.Commit(); err != nil {
|
|
return fmt.Errorf("failed to commit transaction: %v", err)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// Middleware untuk menyimpan store ke context
|
|
func WithStore(store *Store) func(http.Handler) http.Handler {
|
|
return func(next http.Handler) http.Handler {
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
ctx := context.WithValue(r.Context(), "store", store)
|
|
next.ServeHTTP(w, r.WithContext(ctx))
|
|
})
|
|
}
|
|
}
|