mirror of
https://github.com/m1k1o/neko.git
synced 2024-07-24 14:40:50 +12:00
use custom JWT middleware.
This commit is contained in:
parent
c609a28a38
commit
963d210507
1
go.mod
1
go.mod
@ -3,6 +3,7 @@ module demodesk/neko
|
|||||||
go 1.13
|
go 1.13
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/dgrijalva/jwt-go v3.2.0+incompatible
|
||||||
github.com/fsnotify/fsnotify v1.4.9 // indirect
|
github.com/fsnotify/fsnotify v1.4.9 // indirect
|
||||||
github.com/go-chi/chi v4.1.0+incompatible
|
github.com/go-chi/chi v4.1.0+incompatible
|
||||||
github.com/go-chi/render v1.0.1
|
github.com/go-chi/render v1.0.1
|
||||||
|
@ -3,6 +3,7 @@ package member
|
|||||||
import (
|
import (
|
||||||
"github.com/go-chi/chi"
|
"github.com/go-chi/chi"
|
||||||
|
|
||||||
|
"demodesk/neko/internal/api/utils"
|
||||||
"demodesk/neko/internal/types"
|
"demodesk/neko/internal/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -24,18 +25,10 @@ func New(
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (h *MemberHandler) Router(
|
func (h *MemberHandler) Router(
|
||||||
usersOnly func(chi.Router, func(chi.Router)),
|
usersOnly utils.HttpMiddleware,
|
||||||
adminsOnly func(chi.Router, func(chi.Router)),
|
adminsOnly utils.HttpMiddleware,
|
||||||
) *chi.Mux {
|
) *chi.Mux {
|
||||||
r := chi.NewRouter()
|
r := chi.NewRouter()
|
||||||
|
|
||||||
usersOnly(r, func(r chi.Router) {
|
|
||||||
|
|
||||||
})
|
|
||||||
|
|
||||||
adminsOnly(r, func(r chi.Router) {
|
|
||||||
|
|
||||||
})
|
|
||||||
|
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ package room
|
|||||||
import (
|
import (
|
||||||
"github.com/go-chi/chi"
|
"github.com/go-chi/chi"
|
||||||
|
|
||||||
|
"demodesk/neko/internal/api/utils"
|
||||||
"demodesk/neko/internal/types"
|
"demodesk/neko/internal/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -30,18 +31,16 @@ func New(
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (h *RoomHandler) Router(
|
func (h *RoomHandler) Router(
|
||||||
usersOnly func(chi.Router, func(chi.Router)),
|
usersOnly utils.HttpMiddleware,
|
||||||
adminsOnly func(chi.Router, func(chi.Router)),
|
adminsOnly utils.HttpMiddleware,
|
||||||
) *chi.Mux {
|
) *chi.Mux {
|
||||||
r := chi.NewRouter()
|
r := chi.NewRouter()
|
||||||
|
|
||||||
usersOnly(r, func(r chi.Router) {
|
|
||||||
r.Get("/screen", h.ScreenConfiguration)
|
|
||||||
})
|
|
||||||
|
|
||||||
adminsOnly(r, func(r chi.Router) {
|
r.Route("/screen", func(r chi.Router) {
|
||||||
r.Post("/screen", h.ScreenConfigurationChange)
|
r.With(usersOnly).Get("/", h.ScreenConfiguration)
|
||||||
r.Get("/screen/configurations", h.ScreenConfigurationsList)
|
r.With(adminsOnly).Post("/", h.ScreenConfigurationChange)
|
||||||
|
|
||||||
|
r.With(adminsOnly).Get("/configurations", h.ScreenConfigurationsList)
|
||||||
})
|
})
|
||||||
|
|
||||||
return r
|
return r
|
||||||
|
@ -1,13 +1,15 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
"github.com/go-chi/chi"
|
"github.com/go-chi/chi"
|
||||||
"github.com/go-chi/jwtauth"
|
|
||||||
|
|
||||||
"demodesk/neko/internal/api/member"
|
"demodesk/neko/internal/api/member"
|
||||||
"demodesk/neko/internal/api/room"
|
"demodesk/neko/internal/api/room"
|
||||||
"demodesk/neko/internal/types"
|
"demodesk/neko/internal/types"
|
||||||
"demodesk/neko/internal/types/config"
|
"demodesk/neko/internal/types/config"
|
||||||
|
"demodesk/neko/internal/api/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
type API struct {
|
type API struct {
|
||||||
@ -17,8 +19,8 @@ type API struct {
|
|||||||
websocket types.WebSocketHandler
|
websocket types.WebSocketHandler
|
||||||
}
|
}
|
||||||
|
|
||||||
var AdminToken *jwtauth.JWTAuth
|
var AdminToken []byte
|
||||||
var UserToken *jwtauth.JWTAuth
|
var UserToken []byte
|
||||||
|
|
||||||
func New(
|
func New(
|
||||||
sessions types.SessionManager,
|
sessions types.SessionManager,
|
||||||
@ -27,8 +29,8 @@ func New(
|
|||||||
websocket types.WebSocketHandler,
|
websocket types.WebSocketHandler,
|
||||||
conf *config.Server,
|
conf *config.Server,
|
||||||
) *API {
|
) *API {
|
||||||
AdminToken = jwtauth.New("HS256", []byte(conf.AdminToken), nil)
|
AdminToken = []byte(conf.AdminToken)
|
||||||
UserToken = jwtauth.New("HS256", []byte(conf.UserToken), nil)
|
UserToken = []byte(conf.UserToken)
|
||||||
|
|
||||||
return &API{
|
return &API{
|
||||||
sessions: sessions,
|
sessions: sessions,
|
||||||
@ -46,27 +48,10 @@ func (a *API) Mount(r *chi.Mux) {
|
|||||||
r.Mount("/room", roomHandler.Router(UsersOnly, AdminsOnly))
|
r.Mount("/room", roomHandler.Router(UsersOnly, AdminsOnly))
|
||||||
}
|
}
|
||||||
|
|
||||||
func UsersOnly(r chi.Router, protectedRoutes func(r chi.Router)) {
|
func UsersOnly(next http.Handler) http.Handler {
|
||||||
r.Group(func(r chi.Router) {
|
return utils.AuthMiddleware(next, UserToken, AdminToken)
|
||||||
// Verify JWT tokens
|
|
||||||
r.Use(jwtauth.Verifier(UserToken))
|
|
||||||
r.Use(jwtauth.Verifier(AdminToken))
|
|
||||||
|
|
||||||
// Handle valid / invalid tokens.
|
|
||||||
r.Use(jwtauth.Authenticator)
|
|
||||||
|
|
||||||
protectedRoutes(r)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func AdminsOnly(r chi.Router, protectedRoutes func(r chi.Router)) {
|
func AdminsOnly(next http.Handler) http.Handler {
|
||||||
r.Group(func(r chi.Router) {
|
return utils.AuthMiddleware(next, AdminToken)
|
||||||
// Verify JWT token
|
|
||||||
r.Use(jwtauth.Verifier(AdminToken))
|
|
||||||
|
|
||||||
// Handle valid / invalid tokens.
|
|
||||||
r.Use(jwtauth.Authenticator)
|
|
||||||
|
|
||||||
protectedRoutes(r)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
59
internal/api/utils/auth.go
Normal file
59
internal/api/utils/auth.go
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/go-chi/render"
|
||||||
|
"github.com/dgrijalva/jwt-go"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetUserName(r *http.Request) interface{} {
|
||||||
|
props, _ := r.Context().Value("props").(jwt.MapClaims)
|
||||||
|
return props["user_name"]
|
||||||
|
}
|
||||||
|
|
||||||
|
type HttpMiddleware = func(next http.Handler) http.Handler
|
||||||
|
|
||||||
|
func AuthMiddleware(next http.Handler, jwtSecrets ...[]byte) http.Handler {
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
authHeader := strings.Split(r.Header.Get("Authorization"), "Bearer ")
|
||||||
|
if len(authHeader) != 2 {
|
||||||
|
render.Render(w, r, ErrMessage(401, "Malformed JWT token."))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
jwtToken := authHeader[1]
|
||||||
|
var jwtVerified *jwt.Token
|
||||||
|
var err error
|
||||||
|
for _, jwtSecret := range jwtSecrets {
|
||||||
|
jwtVerified, err = jwt.Parse(jwtToken, func(token *jwt.Token) (interface{}, error) {
|
||||||
|
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
|
||||||
|
return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
|
||||||
|
}
|
||||||
|
|
||||||
|
return jwtSecret, nil
|
||||||
|
})
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
render.Render(w, r, ErrMessage(401, "Invalid JWT token."))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if claims, ok := jwtVerified.Claims.(jwt.MapClaims); ok && jwtVerified.Valid {
|
||||||
|
ctx := context.WithValue(r.Context(), "props", claims)
|
||||||
|
// Access context values in handlers like this
|
||||||
|
// props, _ := r.Context().Value("props").(jwt.MapClaims)
|
||||||
|
next.ServeHTTP(w, r.WithContext(ctx))
|
||||||
|
} else {
|
||||||
|
render.Render(w, r, ErrMessage(401, "Unauthorized."))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user