feat: initpage com sync Go + auth + frontend em web/
This commit is contained in:
45
internal/middleware/auth.go
Normal file
45
internal/middleware/auth.go
Normal file
@@ -0,0 +1,45 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
"github.com/alexedwards/scs/v2"
|
||||
)
|
||||
|
||||
type ctxKey string
|
||||
|
||||
const UserIDKey ctxKey = "user_id"
|
||||
|
||||
func AuthRequired(sm *scs.SessionManager) func(http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if !sm.Exists(r.Context(), "user_id") {
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
w.Write([]byte(`{"error":"não autenticado"}`))
|
||||
return
|
||||
}
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func LoadUserID(sm *scs.SessionManager) func(http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
uid, ok := sm.Get(r.Context(), "user_id").(string)
|
||||
if ok {
|
||||
r = r.WithContext(context.WithValue(r.Context(), UserIDKey, uid))
|
||||
}
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func GetUserID(ctx context.Context) string {
|
||||
v := ctx.Value(UserIDKey)
|
||||
if s, ok := v.(string); ok {
|
||||
return s
|
||||
}
|
||||
return ""
|
||||
}
|
||||
66
internal/middleware/ratelimit.go
Normal file
66
internal/middleware/ratelimit.go
Normal file
@@ -0,0 +1,66 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"golang.org/x/time/rate"
|
||||
)
|
||||
|
||||
type IPRateLimiter struct {
|
||||
mu sync.RWMutex
|
||||
limiters map[string]*rate.Limiter
|
||||
r rate.Limit
|
||||
b int
|
||||
}
|
||||
|
||||
func NewIPRateLimiter(r rate.Limit, b int) *IPRateLimiter {
|
||||
return &IPRateLimiter{
|
||||
limiters: make(map[string]*rate.Limiter),
|
||||
r: r,
|
||||
b: b,
|
||||
}
|
||||
}
|
||||
|
||||
func (i *IPRateLimiter) GetLimiter(ip string) *rate.Limiter {
|
||||
i.mu.Lock()
|
||||
defer i.mu.Unlock()
|
||||
if lim, ok := i.limiters[ip]; ok {
|
||||
return lim
|
||||
}
|
||||
lim := rate.NewLimiter(i.r, i.b)
|
||||
i.limiters[ip] = lim
|
||||
return lim
|
||||
}
|
||||
|
||||
func (i *IPRateLimiter) Cleanup() {
|
||||
ticker := time.NewTicker(time.Minute)
|
||||
go func() {
|
||||
for range ticker.C {
|
||||
i.mu.Lock()
|
||||
for k := range i.limiters {
|
||||
delete(i.limiters, k)
|
||||
}
|
||||
i.mu.Unlock()
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func RateLimit(l *IPRateLimiter) func(http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
ip := r.RemoteAddr
|
||||
if xf := r.Header.Get("X-Forwarded-For"); xf != "" {
|
||||
// simples, suficiente pra começar
|
||||
ip = xf
|
||||
}
|
||||
if !l.GetLimiter(ip).Allow() {
|
||||
w.WriteHeader(http.StatusTooManyRequests)
|
||||
w.Write([]byte(`{"error":"muitas tentativas, tente novamente mais tarde"}`))
|
||||
return
|
||||
}
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user