package main
import (
"fmt"
"log"
"net/http"
"github.com/thuongh2/go-security/authn"
"github.com/thuongh2/go-security/core"
"github.com/thuongh2/go-security/crypto/password"
"github.com/thuongh2/go-security/web/middleware"
)
func main() {
// Delegating encoder: encodes new passwords with bcrypt and verifies
// any "{id}hash" value, so an existing password column with a different
// algorithm prefix keeps working unchanged.
encoder := password.NewDelegatingEncoder(password.IDBcrypt)
// In-memory users. PasswordHash is pre-encoded with the same encoder.
users := authn.NewInMemoryUserService()
users.Add(authn.User{
Username: "user",
PasswordHash: mustEncode(encoder, "userpw"),
Authorities: core.Roles("USER"),
})
users.Add(authn.User{
Username: "admin",
PasswordHash: mustEncode(encoder, "adminpw"),
Authorities: core.Roles("USER", "ADMIN"),
})
// Manager backed by the password (Dao) provider.
manager := authn.NewManager([]authn.Provider{
authn.NewPasswordProvider(users, encoder),
})
// Application routes.
mux := http.NewServeMux()
mux.HandleFunc("/public", func(w http.ResponseWriter, _ *http.Request) {
fmt.Fprintln(w, "public: no authentication required")
})
mux.Handle("/api/me", middleware.RequireAuthenticated()(http.HandlerFunc(
func(w http.ResponseWriter, r *http.Request) {
auth := core.MustAuthentication(r.Context())
fmt.Fprintf(w, "name=%s authorities=%v\n", auth.Name(), auth.Authorities())
},
)))
mux.Handle("/admin", middleware.RequireRole("ADMIN")(http.HandlerFunc(
func(w http.ResponseWriter, _ *http.Request) {
fmt.Fprintln(w, "admin: you have ROLE_ADMIN")
},
)))
// Compose the security chain and wrap the routes.
chain := middleware.New(
middleware.SecurityHeaders(),
middleware.BasicAuth(manager, "go-security demo"),
)
handler := chain.Then(mux)
addr := ":8080"
log.Printf("listening on %s", addr)
if err := http.ListenAndServe(addr, handler); err != nil {
log.Fatal(err)
}
}
func mustEncode(enc password.Encoder, raw string) string {
h, err := enc.Encode(raw)
if err != nil {
panic(err)
}
return h
}