package authtoken import ( "RenewCMS/api/pkg/apperr" "context" "net/http" "strings" ) const ( cookieName = "jwt" bearerPrefix = "bearer " ) type contextKey struct{} type verdict struct { claims Claims err error } func Verifier(auth *Auth) func(http.Handler) http.Handler { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { claims, err := auth.Decode(tokenFromRequest(r)) next.ServeHTTP(w, r.WithContext(NewContext(r.Context(), claims, err))) }) } } func Authenticator(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if _, err := FromContext(r.Context()); err != nil { http.Error(w, apperr.UnauthorizedErrorMessage, http.StatusUnauthorized) return } next.ServeHTTP(w, r) }) } func NewContext(ctx context.Context, claims Claims, err error) context.Context { return context.WithValue(ctx, contextKey{}, verdict{claims: claims, err: err}) } func FromContext(ctx context.Context) (Claims, error) { stored, ok := ctx.Value(contextKey{}).(verdict) switch { case !ok: return nil, ErrNoToken case stored.err != nil: return nil, stored.err case stored.claims == nil: return nil, ErrNoToken } return stored.claims, nil } func tokenFromRequest(r *http.Request) string { if token := tokenFromHeader(r); token != "" { return token } return tokenFromCookie(r) } func tokenFromHeader(r *http.Request) string { header := r.Header.Get("Authorization") if len(header) <= len(bearerPrefix) || !strings.EqualFold(header[:len(bearerPrefix)], bearerPrefix) { return "" } return header[len(bearerPrefix):] } func tokenFromCookie(r *http.Request) string { cookie, err := r.Cookie(cookieName) if err != nil { return "" } return cookie.Value }