initial commit
This commit is contained in:
commit
1253955070
75 changed files with 13972 additions and 0 deletions
63
api/internal/auth/middleware.go
Normal file
63
api/internal/auth/middleware.go
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
package auth
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type ctxKey struct{}
|
||||
|
||||
// WithUser stores the verified identity on the request context.
|
||||
func WithUser(ctx context.Context, u User) context.Context {
|
||||
return context.WithValue(ctx, ctxKey{}, u)
|
||||
}
|
||||
|
||||
// FromContext returns the identity attached by the middleware.
|
||||
func FromContext(ctx context.Context) (User, bool) {
|
||||
u, ok := ctx.Value(ctxKey{}).(User)
|
||||
return u, ok
|
||||
}
|
||||
|
||||
// Middleware verifies the Authorization header and rejects requests that carry
|
||||
// no usable credential.
|
||||
type Middleware struct {
|
||||
verifier Verifier
|
||||
}
|
||||
|
||||
// NewMiddleware returns middleware backed by the verifier.
|
||||
func NewMiddleware(v Verifier) *Middleware {
|
||||
return &Middleware{verifier: v}
|
||||
}
|
||||
|
||||
// Wrap protects h, making the verified identity available to it.
|
||||
func (m *Middleware) Wrap(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
token, err := BearerToken(r.Header.Get("Authorization"))
|
||||
if err != nil {
|
||||
unauthorized(w, err)
|
||||
return
|
||||
}
|
||||
user, err := m.verifier.Verify(r.Context(), token)
|
||||
if err != nil {
|
||||
unauthorized(w, err)
|
||||
return
|
||||
}
|
||||
next.ServeHTTP(w, r.WithContext(WithUser(r.Context(), user)))
|
||||
})
|
||||
}
|
||||
|
||||
// WrapFunc protects a handler function.
|
||||
func (m *Middleware) WrapFunc(next http.HandlerFunc) http.HandlerFunc {
|
||||
return m.Wrap(next).ServeHTTP
|
||||
}
|
||||
|
||||
func unauthorized(w http.ResponseWriter, err error) {
|
||||
w.Header().Set("WWW-Authenticate", `Bearer realm="go-places"`)
|
||||
// The response deliberately does not echo the reason.
|
||||
if errors.Is(err, ErrMissingToken) {
|
||||
http.Error(w, "unauthorized: a bearer token is required", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
http.Error(w, "unauthorized: the token was rejected", http.StatusUnauthorized)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue