Skip to content

Instantly share code, notes, and snippets.

@nanoninja
Created July 11, 2017 21:58
Show Gist options
  • Save nanoninja/2b9fd0b734fe48589811eabe9a68723c to your computer and use it in GitHub Desktop.
Save nanoninja/2b9fd0b734fe48589811eabe9a68723c to your computer and use it in GitHub Desktop.
Go Basic Authentication with timeout
package main
import (
"fmt"
"net/http"
"time"
)
var Realm = "Authorization Required"
func main() {
users := map[string]string{
"foo": "bar",
"bar": "foo",
}
basicTimeout := NewBasicTimeout(Realm, users, 10*time.Second)
next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Dashboard")
})
http.Handle("/admin", basicTimeout.Use(next))
http.ListenAndServe(":3000", nil)
}
func WriteHeader(w http.ResponseWriter, realm string) {
w.Header().Add("WWW-Authenticate", `Basic realm="`+realm+`"`)
w.WriteHeader(http.StatusUnauthorized)
}
func Require(realm string) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
WriteHeader(w, realm)
w.Write([]byte(http.StatusText(http.StatusUnauthorized)))
})
}
type BasicTimeout struct {
Realm string
Duration time.Duration
Expires time.Time
Logged bool
Users map[string]string
}
func NewBasicTimeout(realm string, users map[string]string, d time.Duration) *BasicTimeout {
return &BasicTimeout{
Realm: realm,
Duration: d,
Logged: false,
Users: users,
}
}
func (ba *BasicTimeout) Use(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
username, password, ok := r.BasicAuth()
if !ok {
Require(Realm).ServeHTTP(w, r)
return
}
if ba.Logged == false {
ba.Expires = time.Now().Add(ba.Duration)
}
if time.Now().After(ba.Expires) {
Require(Realm).ServeHTTP(w, r)
ba.Logged = false
return
}
if pass, ok := ba.Users[username]; ok && pass == password {
ba.Logged = true
next.ServeHTTP(w, r)
return
}
})
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment