From 8a86b8f7bd6621ad0725350b1aa5ef94e715aced Mon Sep 17 00:00:00 2001 From: a-wing <1@233.email> Date: Mon, 1 Jan 2024 01:57:39 +0800 Subject: [PATCH] feat(server): add auth jwt --- go.mod | 1 + go.sum | 2 ++ server/api/api.go | 23 +++++++++------ server/api/middleware/middleware.go | 35 +++++++++++++++++++++++ server/api/v1/handler.go | 4 ++- server/api/v1/stream.go | 2 +- server/api/v1/user.go | 44 +++++++++++++++++++++++++++++ server/config.go | 1 + server/daemon/daemon.go | 2 +- 9 files changed, 103 insertions(+), 11 deletions(-) create mode 100644 server/api/middleware/middleware.go create mode 100644 server/api/v1/user.go diff --git a/go.mod b/go.mod index 9a07c0b..442df15 100644 --- a/go.mod +++ b/go.mod @@ -7,6 +7,7 @@ require ( github.com/go-chi/chi/v5 v5.0.10 github.com/go-chi/render v1.0.3 github.com/gofrs/uuid/v5 v5.0.0 + github.com/golang-jwt/jwt/v5 v5.2.0 github.com/redis/go-redis/v9 v9.3.1 ) diff --git a/go.sum b/go.sum index bc2dcd6..a6b2ce7 100644 --- a/go.sum +++ b/go.sum @@ -16,5 +16,7 @@ github.com/go-chi/render v1.0.3 h1:AsXqd2a1/INaIfUSKq3G5uA8weYx20FOsM7uSoCyyt4= github.com/go-chi/render v1.0.3/go.mod h1:/gr3hVkmYR0YlEy3LxCuVRFzEu9Ruok+gFqbIofjao0= github.com/gofrs/uuid/v5 v5.0.0 h1:p544++a97kEL+svbcFbCQVM9KFu0Yo25UoISXGNNH9M= github.com/gofrs/uuid/v5 v5.0.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8= +github.com/golang-jwt/jwt/v5 v5.2.0 h1:d/ix8ftRUorsN+5eMIlF4T6J8CAt9rch3My2winC1Jw= +github.com/golang-jwt/jwt/v5 v5.2.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/redis/go-redis/v9 v9.3.1 h1:KqdY8U+3X6z+iACvumCNxnoluToB+9Me+TvyFa21Mds= github.com/redis/go-redis/v9 v9.3.1/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M= diff --git a/server/api/api.go b/server/api/api.go index 9f8caa2..d3c8e31 100644 --- a/server/api/api.go +++ b/server/api/api.go @@ -5,6 +5,7 @@ import ( "net/http/httputil" "net/url" + woomMiddleware "woom/server/api/middleware" "woom/server/api/v1" "woom/server/helper" "woom/static" @@ -23,7 +24,7 @@ func handler(p http.Handler, token string) func(http.ResponseWriter, *http.Reque } } -func NewApi(rdb *redis.Client, live777Url string, live777Token string) http.Handler { +func NewApi(rdb *redis.Client, secret string, live777Url string, live777Token string) http.Handler { remote, err := url.Parse(live777Url) if err != nil { panic(err) @@ -33,14 +34,20 @@ func NewApi(rdb *redis.Client, live777Url string, live777Token string) http.Hand r := chi.NewRouter() r.Use(middleware.Logger) - handle := v1.NewHandler(rdb) + handle := v1.NewHandler(rdb, secret) - r.Post("/room/", handle.CreateRoom) - r.Get("/room/{roomId}", handle.ShowRoom) - //r.Patch("/room/{roomId}", handle.UpdateRoom) - r.Post("/room/{roomId}/stream", handle.CreateRoomStream) - r.Patch("/room/{roomId}/stream/{streamId}", handle.UpdateRoomStream) - r.Delete("/room/{roomId}/stream/{streamId}", handle.DestroyRoomStream) + r.Group(func(r chi.Router) { + r.Use(woomMiddleware.JWTAuth(secret)) + + r.Post("/room/", handle.CreateRoom) + r.Get("/room/{roomId}", handle.ShowRoom) + //r.Patch("/room/{roomId}", handle.UpdateRoom) + r.Post("/room/{roomId}/stream", handle.CreateRoomStream) + r.Patch("/room/{roomId}/stream/{streamId}", handle.UpdateRoomStream) + r.Delete("/room/{roomId}/stream/{streamId}", handle.DestroyRoomStream) + }) + + r.Post("/user/", handle.CreateUser) //r.Post("/room/{roomId}/message", handle.CreateMessage) //r.Get("/room/{roomId}/message", handle.ShowMessage) diff --git a/server/api/middleware/middleware.go b/server/api/middleware/middleware.go new file mode 100644 index 0000000..cee1ec8 --- /dev/null +++ b/server/api/middleware/middleware.go @@ -0,0 +1,35 @@ +package middleware + +import ( + "net/http" + "strings" + + "github.com/golang-jwt/jwt/v5" +) + +func JWTAuth(secret string) func(next http.Handler) http.Handler { + return func(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + tokenString := TokenFromHeader(r) + _, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) { + return []byte(secret), nil + }) + + if err != nil { + w.WriteHeader(http.StatusUnauthorized) + w.Write([]byte(err.Error())) + return + } + next.ServeHTTP(w, r) + }) + } +} + +func TokenFromHeader(r *http.Request) string { + // Get token from authorization header. + bearer := r.Header.Get("Authorization") + if len(bearer) > 7 && strings.ToUpper(bearer[0:6]) == "BEARER" { + return bearer[7:] + } + return "" +} diff --git a/server/api/v1/handler.go b/server/api/v1/handler.go index b693e83..82620b8 100644 --- a/server/api/v1/handler.go +++ b/server/api/v1/handler.go @@ -6,10 +6,12 @@ import ( type Handler struct { rdb *redis.Client + key string } -func NewHandler(rdb *redis.Client) *Handler { +func NewHandler(rdb *redis.Client, secret string) *Handler { return &Handler{ rdb: rdb, + key: secret, } } diff --git a/server/api/v1/stream.go b/server/api/v1/stream.go index 08cd42b..82a3d72 100644 --- a/server/api/v1/stream.go +++ b/server/api/v1/stream.go @@ -56,7 +56,7 @@ func (h *Handler) DestroyRoomStream(w http.ResponseWriter, r *http.Request) { roomId := chi.URLParam(r, "roomId") streamId := chi.URLParam(r, "streamId") - if err := h.rdb.HDel(context.TODO(), roomId, streamId,).Err(); err != nil { + if err := h.rdb.HDel(context.TODO(), roomId, streamId).Err(); err != nil { w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(err.Error())) return diff --git a/server/api/v1/user.go b/server/api/v1/user.go new file mode 100644 index 0000000..25608b2 --- /dev/null +++ b/server/api/v1/user.go @@ -0,0 +1,44 @@ +package v1 + +import ( + "net/http" + "time" + + "github.com/go-chi/render" + "github.com/golang-jwt/jwt/v5" +) + +func (h *Handler) CreateUser(w http.ResponseWriter, r *http.Request) { + streamId, err := h.helperCreateStreamId() + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte(err.Error())) + return + } + + type Claims struct { + Id string `json:"id"` + jwt.RegisteredClaims + } + + timeNow := time.Now() + token := jwt.NewWithClaims(jwt.SigningMethodHS512, &Claims{ + streamId, + jwt.RegisteredClaims{ + ExpiresAt: jwt.NewNumericDate(timeNow.Add(24 * time.Hour)), + IssuedAt: jwt.NewNumericDate(timeNow), + NotBefore: jwt.NewNumericDate(timeNow), + }, + }) + tokenString, err := token.SignedString([]byte(h.key)) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte(err.Error())) + return + } + + render.JSON(w, r, map[string]string{ + "streamId": streamId, + "token": tokenString, + }) +} diff --git a/server/config.go b/server/config.go index adfc19b..09ed708 100644 --- a/server/config.go +++ b/server/config.go @@ -1,6 +1,7 @@ package server type Config struct { + Secret string `env:"SECRET" envDefault:"woom"` Port string `env:"PORT" envDefault:"4000"` RedisUrl string `env:"REDIS_URL" envDefault:"redis://localhost:6379/0"` Live777Url string `env:"LIVE777_URL" envDefault:"http://localhost:7777"` diff --git a/server/daemon/daemon.go b/server/daemon/daemon.go index 1bdae36..e1b49f0 100644 --- a/server/daemon/daemon.go +++ b/server/daemon/daemon.go @@ -30,7 +30,7 @@ func Daemon(ctx context.Context) { rdb := newRdbClient(cfg.RedisUrl) log.Println(rdb) - handler := api.NewApi(rdb, cfg.Live777Url, cfg.Live777Token) + handler := api.NewApi(rdb, cfg.Secret, cfg.Live777Url, cfg.Live777Token) log.Println("=== started ===") log.Panicln(http.ListenAndServe(":"+cfg.Port, handler))