...
1 package webserver
2
3 import (
4 "errors"
5 "fmt"
6 "net/http"
7 "time"
8
9 jsoniter "github.com/json-iterator/go"
10
11 "github.com/golang-jwt/jwt/v5"
12 )
13
14 type loginReq struct {
15 Username string `json:"user"`
16 Password string `json:"password"`
17 }
18
19 func (Server *WebUIServer) IsCorrectPassword(lr loginReq) bool {
20 return (Server.WebUser+Server.WebPassword == "") ||
21 (Server.WebUser == lr.Username && Server.WebPassword == lr.Password)
22 }
23
24 func (Server *WebUIServer) handleLogin(w http.ResponseWriter, r *http.Request) {
25 var (
26 err error
27 lr loginReq
28 token string
29 )
30
31 defer func() {
32 if err != nil {
33 http.Error(w, err.Error(), http.StatusInternalServerError)
34 }
35 }()
36
37 switch r.Method {
38 case "POST":
39 if err = jsoniter.ConfigFastest.NewDecoder(r.Body).Decode(&lr); err != nil {
40 return
41 }
42 if !Server.IsCorrectPassword(lr) {
43 http.Error(w, "can not authenticate this user", http.StatusUnauthorized)
44 return
45 }
46 if token, err = generateJWT(lr.Username); err != nil {
47 return
48 }
49 _, err = w.Write([]byte(token))
50
51 case "GET":
52 fmt.Fprintf(w, "only POST methods is allowed.")
53 return
54 }
55 }
56
57 type EnsureAuth struct {
58 handler http.HandlerFunc
59 }
60
61 func (ea *EnsureAuth) ServeHTTP(w http.ResponseWriter, r *http.Request) {
62 if err := validateToken(r); err != nil {
63 http.Error(w, err.Error(), http.StatusUnauthorized)
64 return
65 }
66 ea.handler(w, r)
67 }
68
69 func NewEnsureAuth(handlerToWrap http.HandlerFunc) *EnsureAuth {
70 return &EnsureAuth{handlerToWrap}
71 }
72
73 var sampleSecretKey = []byte("5m3R7K4754p4m")
74
75 func generateJWT(username string) (string, error) {
76 token := jwt.New(jwt.SigningMethodHS256)
77 claims := token.Claims.(jwt.MapClaims)
78
79 claims["authorized"] = true
80 claims["username"] = username
81 claims["exp"] = time.Now().Add(time.Hour * 8).Unix()
82
83 return token.SignedString(sampleSecretKey)
84 }
85
86 func validateToken(r *http.Request) (err error) {
87 var t string
88 if r.Header["Token"] == nil {
89 t = r.URL.Query().Get("Token")
90 } else {
91 t = r.Header["Token"][0]
92 }
93 if t == "" {
94 return errors.New("can not find token in header")
95 }
96
97 _, err = jwt.Parse(t,
98 func(_ *jwt.Token) (any, error) {
99 return sampleSecretKey, nil
100 },
101 jwt.WithExpirationRequired(),
102 jwt.WithValidMethods([]string{jwt.SigningMethodHS256.Alg()}))
103 return err
104 }
105