features/token-things #2
@ -49,6 +49,7 @@ func NewServer(ctx context.Context, configs config.Configs, apiClient apiclient.
|
||||
router.Pre(middleware.Logger())
|
||||
router.Pre(middleware.Recover())
|
||||
router.Use(middleware.Static("/internal/static"))
|
||||
//router.Use(RefreshJwtMiddleware(apiClient))
|
||||
|
||||
router.GET("/", s.HomeIndex)
|
||||
router.GET("/about", s.HomeAbout)
|
||||
@ -57,57 +58,23 @@ func NewServer(ctx context.Context, configs config.Configs, apiClient apiclient.
|
||||
debug.GET("/cookies", s.DebugCookies)
|
||||
|
||||
articles := router.Group("/articles")
|
||||
//articles.Use(ValidateJwtMiddleware(configs.JwtSecret))
|
||||
articles.GET("", s.ArticlesList)
|
||||
|
||||
sources := router.Group("/sources")
|
||||
//sources.Use(ValidateJwtMiddleware(configs.JwtSecret))
|
||||
sources.GET("", s.ListAllSources)
|
||||
sources.GET("/add", s.AddSource)
|
||||
|
||||
users := router.Group("/users")
|
||||
users.GET("/login", s.UserLogin)
|
||||
users.POST("/login", s.UserAfterLogin)
|
||||
users.GET("/signup", s.UserSignUp)
|
||||
users.POST("/signup", s.UserAfterSignUp)
|
||||
users.Use(ValidateJwtMiddleware(configs.JwtSecret))
|
||||
users.GET("/logout", s.UsersLogout)
|
||||
users.GET("/profile", s.UserProfile)
|
||||
|
||||
s.Router = router
|
||||
return s
|
||||
}
|
||||
|
||||
// If the token is not valid then an json error will be returned.
|
||||
// If the token has the wrong scope, a json error will be returned.
|
||||
// If the token passes all the checks, it is valid and is returned back to the caller.
|
||||
//func (s *Handler) ValidateJwtToken(c echo.Context, requiredScope string) (JwtToken, error) {
|
||||
// token, err := s.getJwtTokenFromContext(c)
|
||||
// if err != nil {
|
||||
// s.WriteMessage(c, ErrJwtMissing, http.StatusUnauthorized)
|
||||
// }
|
||||
//
|
||||
// err = token.hasExpired()
|
||||
// if err != nil {
|
||||
// return JwtToken{}, errors.New(ErrJwtExpired)
|
||||
// //s.WriteMessage(c, ErrJwtExpired, http.StatusUnauthorized)
|
||||
// }
|
||||
//
|
||||
// err = token.hasScope(requiredScope)
|
||||
// if err != nil {
|
||||
// return JwtToken{}, errors.New(ErrJwtScopeMissing)
|
||||
// //s.WriteMessage(c, ErrJwtScopeMissing, http.StatusUnauthorized)
|
||||
// }
|
||||
//
|
||||
// if token.Iss != s.config.ServerAddress {
|
||||
// return JwtToken{}, errors.New(ErrJwtInvalidIssuer)
|
||||
// //s.WriteMessage(c, ErrJwtInvalidIssuer, http.StatusUnauthorized)
|
||||
// }
|
||||
//
|
||||
// return token, nil
|
||||
//}
|
||||
|
||||
//func (s *Handler) GetUserIdFromJwtToken(c echo.Context) int64 {
|
||||
// token, err := s.getJwtTokenFromContext(c)
|
||||
// if err != nil {
|
||||
// s.WriteMessage(c, ErrJwtMissing, http.StatusUnauthorized)
|
||||
// }
|
||||
//
|
||||
// return token.GetUserId()
|
||||
//}
|
||||
|
64
internal/handlers/middleware.go
Normal file
64
internal/handlers/middleware.go
Normal file
@ -0,0 +1,64 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"git.jamestombleson.com/jtom38/newsbot-portal/apiclient"
|
||||
"git.jamestombleson.com/jtom38/newsbot-portal/internal/domain"
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
"github.com/labstack/echo/v4"
|
||||
)
|
||||
|
||||
func ValidateJwtMiddleware(jwtSecret string) echo.MiddlewareFunc {
|
||||
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
||||
return func(c echo.Context) error {
|
||||
cookie, err := c.Cookie(domain.CookieToken)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if cookie.Value == "" {
|
||||
return echo.NewHTTPError(401, "Authorization token is missing.")
|
||||
}
|
||||
|
||||
token, err := jwt.ParseWithClaims(cookie.Value, &jwtToken{}, func(token *jwt.Token) (interface{}, error) {
|
||||
return []byte(jwtSecret), nil
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !token.Valid {
|
||||
return echo.NewHTTPError(401, "Invalid authorization token.")
|
||||
//return errors.New("invalid jwt token")
|
||||
}
|
||||
|
||||
claims := token.Claims.(*jwtToken)
|
||||
if !claims.Exp.After(time.Now()) {
|
||||
return echo.NewHTTPError(401, "Your Authorization token has expired.")
|
||||
//return errors.New("the jwt token has expired")
|
||||
}
|
||||
//if claims.Iss != issuer {
|
||||
// return jwtToken{}, errors.New("the issuer was invalid")
|
||||
//}
|
||||
|
||||
return next(c)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func RefreshJwtMiddleware(api apiclient.ApiClient) echo.MiddlewareFunc {
|
||||
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
||||
return func(c echo.Context) error {
|
||||
resp, err := api.Users.RefreshJwtTokenFromContext(c)
|
||||
if err != nil {
|
||||
return next(c)
|
||||
}
|
||||
|
||||
SetCookie(c, domain.CookieToken, resp.Token, "/")
|
||||
SetCookie(c, domain.CookieRefreshToken, resp.RefreshToken, "/")
|
||||
|
||||
return next(c)
|
||||
}
|
||||
}
|
||||
}
|
@ -4,9 +4,12 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"git.jamestombleson.com/jtom38/newsbot-portal/internal/config"
|
||||
"git.jamestombleson.com/jtom38/newsbot-portal/internal/domain"
|
||||
"git.jamestombleson.com/jtom38/newsbot-portal/internal/views/layout"
|
||||
"github.com/a-h/templ"
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
"github.com/labstack/echo/v4"
|
||||
@ -33,7 +36,31 @@ type jwtToken struct {
|
||||
jwt.RegisteredClaims
|
||||
}
|
||||
|
||||
func ValidateJwt(ctx echo.Context, sharedSecret, issuer string) (jwtToken, error) {
|
||||
func IsLoggedIn(ctx echo.Context) error {
|
||||
_, err := GetUserInfo(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func HasValidScope(ctx echo.Context, scope string) error {
|
||||
token, err := GetUserInfo(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
userScopes := strings.Join(token.Scopes, ",")
|
||||
if strings.Contains(userScopes, scope) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return errors.New("required permission is missing")
|
||||
}
|
||||
|
||||
func GetUserInfo(ctx echo.Context) (jwtToken, error) {
|
||||
cfg := config.New()
|
||||
cookie, err := ctx.Cookie(domain.CookieToken)
|
||||
if err != nil {
|
||||
return jwtToken{}, err
|
||||
@ -44,7 +71,7 @@ func ValidateJwt(ctx echo.Context, sharedSecret, issuer string) (jwtToken, error
|
||||
}
|
||||
|
||||
token, err := jwt.ParseWithClaims(cookie.Value, &jwtToken{}, func(token *jwt.Token) (interface{}, error) {
|
||||
return []byte(sharedSecret), nil
|
||||
return []byte(cfg.JwtSecret), nil
|
||||
})
|
||||
if err != nil {
|
||||
return jwtToken{}, err
|
||||
@ -58,9 +85,6 @@ func ValidateJwt(ctx echo.Context, sharedSecret, issuer string) (jwtToken, error
|
||||
if !claims.Exp.After(time.Now()) {
|
||||
return jwtToken{}, errors.New("the jwt token has expired")
|
||||
}
|
||||
//if claims.Iss != issuer {
|
||||
// return jwtToken{}, errors.New("the issuer was invalid")
|
||||
//}
|
||||
|
||||
return *claims, nil
|
||||
}
|
||||
@ -90,3 +114,22 @@ func Render(ctx echo.Context, statusCode int, t templ.Component) error {
|
||||
|
||||
return t.Render(request, ctx.Response().Writer)
|
||||
}
|
||||
|
||||
func RenderError(ctx echo.Context, err error) error {
|
||||
var t templ.Component = layout.Error(err)
|
||||
ctx.Response().Writer.WriteHeader(200)
|
||||
ctx.Response().Header().Set(echo.HeaderContentType, echo.MIMETextHTML)
|
||||
|
||||
// take the request context and make it a var
|
||||
request := ctx.Request().Context()
|
||||
|
||||
//Check to see if we the echo context has the cookie we are looking for, if so, create a new context based on what we had and add the value
|
||||
username, err := ctx.Cookie(domain.CookieUser)
|
||||
if err == nil {
|
||||
request = context.WithValue(request, domain.UserNameContext, username.Value)
|
||||
} else {
|
||||
request = context.WithValue(request, domain.UserNameContext, "")
|
||||
}
|
||||
|
||||
return t.Render(request, ctx.Response().Writer)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user