84 lines
1.8 KiB
Go
84 lines
1.8 KiB
Go
package auth
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
)
|
|
|
|
type roleKey struct{}
|
|
|
|
type Role int
|
|
|
|
const (
|
|
RoleReader Role = iota
|
|
RoleWriter
|
|
RoleAdmin
|
|
)
|
|
|
|
func ParseRole(s string) Role {
|
|
switch s {
|
|
case "admin":
|
|
return RoleAdmin
|
|
case "writer":
|
|
return RoleWriter
|
|
default:
|
|
return RoleReader
|
|
}
|
|
}
|
|
|
|
func (r Role) CanRead() bool { return true }
|
|
func (r Role) CanWrite() bool { return r >= RoleWriter }
|
|
func (r Role) CanDDL() bool { return r >= RoleAdmin }
|
|
|
|
type Handler struct {
|
|
role Role
|
|
}
|
|
|
|
func New(roleStr string) *Handler {
|
|
return &Handler{role: ParseRole(roleStr)}
|
|
}
|
|
|
|
func (h *Handler) Middleware(next http.Handler) http.Handler {
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
ctx := context.WithValue(r.Context(), roleKey{}, h.role)
|
|
next.ServeHTTP(w, r.WithContext(ctx))
|
|
})
|
|
}
|
|
|
|
func RoleFromContext(ctx context.Context) Role {
|
|
if r, ok := ctx.Value(roleKey{}).(Role); ok {
|
|
return r
|
|
}
|
|
return RoleReader
|
|
}
|
|
|
|
func RequireWrite(next http.HandlerFunc) http.HandlerFunc {
|
|
return func(w http.ResponseWriter, r *http.Request) {
|
|
if !RoleFromContext(r.Context()).CanWrite() {
|
|
http.Error(w, `{"error":"forbidden: write access required"}`, http.StatusForbidden)
|
|
return
|
|
}
|
|
next(w, r)
|
|
}
|
|
}
|
|
|
|
func RequireDDL(next http.HandlerFunc) http.HandlerFunc {
|
|
return func(w http.ResponseWriter, r *http.Request) {
|
|
if !RoleFromContext(r.Context()).CanDDL() {
|
|
http.Error(w, `{"error":"forbidden: admin access required"}`, http.StatusForbidden)
|
|
return
|
|
}
|
|
next(w, r)
|
|
}
|
|
}
|
|
|
|
func RequireWriteMiddleware(next http.Handler) http.Handler {
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
if !RoleFromContext(r.Context()).CanWrite() {
|
|
http.Error(w, `{"error":"forbidden: write access required"}`, http.StatusForbidden)
|
|
return
|
|
}
|
|
next.ServeHTTP(w, r)
|
|
})
|
|
}
|