mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-05-24 02:02:36 -04:00
Add /jwt route
This commit is contained in:
parent
95da0184a0
commit
e197062f64
@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"time"
|
||||
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
"github.com/zoriya/kyoo/keibi/dbc"
|
||||
@ -13,6 +14,7 @@ type Configuration struct {
|
||||
JwtSecret []byte
|
||||
Issuer string
|
||||
DefaultClaims jwt.MapClaims
|
||||
ExpirationDelay time.Duration
|
||||
}
|
||||
|
||||
const (
|
||||
|
@ -126,6 +126,10 @@ type Handler struct {
|
||||
|
||||
// @host kyoo.zoriya.dev
|
||||
// @BasePath /auth
|
||||
|
||||
// @securityDefinitions.apiKey Token
|
||||
// @in header
|
||||
// @name Authorization
|
||||
func main() {
|
||||
e := echo.New()
|
||||
e.Use(middleware.Logger())
|
||||
@ -151,6 +155,7 @@ func main() {
|
||||
e.GET("/users", h.ListUsers)
|
||||
e.POST("/users", h.Register)
|
||||
|
||||
e.GET("/jwt", h.CreateJwt)
|
||||
e.POST("/session", h.Login)
|
||||
|
||||
e.GET("/swagger/*", echoSwagger.WrapHandler)
|
||||
|
@ -7,6 +7,7 @@ import (
|
||||
"encoding/base64"
|
||||
"maps"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/alexedwards/argon2id"
|
||||
@ -17,7 +18,7 @@ import (
|
||||
|
||||
type LoginDto struct {
|
||||
// Either the email or the username.
|
||||
Login string `json:"login" validate:"required"`
|
||||
Login string `json:"login" validate:"required"`
|
||||
// Password of the account.
|
||||
Password string `json:"password" validate:"required"`
|
||||
}
|
||||
@ -82,7 +83,7 @@ func (h *Handler) createSession(c echo.Context, user *User) error {
|
||||
|
||||
session, err := h.db.CreateSession(ctx, dbc.CreateSessionParams{
|
||||
Token: base64.StdEncoding.EncodeToString(id),
|
||||
UserID: user.Id,
|
||||
UserId: user.Id,
|
||||
Device: device,
|
||||
})
|
||||
if err != nil {
|
||||
@ -91,20 +92,43 @@ func (h *Handler) createSession(c echo.Context, user *User) error {
|
||||
return c.JSON(201, session)
|
||||
}
|
||||
|
||||
type Jwt struct {
|
||||
// The jwt token you can use for all authorized call to either keibi or other services.
|
||||
Token string `json:"token"`
|
||||
}
|
||||
|
||||
// @Summary Get JWT
|
||||
// @Description Convert a session token to a short lived JWT.
|
||||
// @Tags sessions
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param user body LoginDto false "Account informations"
|
||||
// @Success 200 {object} dbc.Session
|
||||
// @Failure 400 {object} problem.Problem "Invalid login body"
|
||||
// @Failure 400 {object} problem.Problem "Invalid password"
|
||||
// @Failure 404 {object} problem.Problem "Account does not exists"
|
||||
// @Security Token
|
||||
// @Success 200 {object} Jwt
|
||||
// @Failure 401 {object} problem.Problem "Missing session token"
|
||||
// @Failure 403 {object} problem.Problem "Invalid session token (or expired)"
|
||||
// @Router /jwt [get]
|
||||
func (h *Handler) CreateJwt(c echo.Context, user *User) error {
|
||||
claims := maps.Clone(user.Claims)
|
||||
claims["sub"] = user.Id.String()
|
||||
func (h *Handler) CreateJwt(c echo.Context) error {
|
||||
auth := c.Request().Header.Get("Authorization")
|
||||
if !strings.HasPrefix(auth, "Bearer ") {
|
||||
return echo.NewHTTPError(http.StatusUnauthorized, "Missing session token")
|
||||
}
|
||||
token := auth[len("Bearer "):]
|
||||
|
||||
session, err := h.db.GetUserFromToken(context.Background(), token)
|
||||
if err != nil {
|
||||
return echo.NewHTTPError(http.StatusForbidden, "Invalid token")
|
||||
}
|
||||
if session.LastUsed.Add(h.config.ExpirationDelay).Compare(time.Now().UTC()) < 0 {
|
||||
return echo.NewHTTPError(http.StatusForbidden, "Token has expired")
|
||||
}
|
||||
|
||||
go func() {
|
||||
h.db.TouchSession(context.Background(), session.Id)
|
||||
h.db.TouchUser(context.Background(), session.User.Id)
|
||||
}()
|
||||
|
||||
claims := maps.Clone(session.User.Claims)
|
||||
claims["sub"] = session.User.Id.String()
|
||||
claims["iss"] = h.config.Issuer
|
||||
claims["exp"] = &jwt.NumericDate{
|
||||
Time: time.Now().UTC().Add(time.Hour),
|
||||
@ -112,12 +136,12 @@ func (h *Handler) CreateJwt(c echo.Context, user *User) error {
|
||||
claims["iss"] = &jwt.NumericDate{
|
||||
Time: time.Now().UTC(),
|
||||
}
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
||||
t, err := token.SignedString(h.config.JwtSecret)
|
||||
jwt := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
||||
t, err := jwt.SignedString(h.config.JwtSecret)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return c.JSON(http.StatusOK, echo.Map{
|
||||
"token": t,
|
||||
return c.JSON(http.StatusOK, Jwt{
|
||||
Token: t,
|
||||
})
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
-- name: GetUserFromToken :one
|
||||
select
|
||||
u.*
|
||||
s.id, s.last_used, sqlc.embed(u)
|
||||
from
|
||||
users as u
|
||||
left join sessions as s on u.id = s.user_id
|
||||
inner join sessions as s on u.id = s.user_id
|
||||
where
|
||||
s.token = $1
|
||||
limit 1;
|
||||
|
@ -38,6 +38,14 @@ where
|
||||
or username = sqlc.arg(login)
|
||||
limit 1;
|
||||
|
||||
-- name: TouchUser :exec
|
||||
update
|
||||
users
|
||||
set
|
||||
last_used = now()::timestamptz
|
||||
where
|
||||
id = $1;
|
||||
|
||||
-- name: CreateUser :one
|
||||
insert into users(username, email, password, claims)
|
||||
values ($1, $2, $3, $4)
|
||||
|
@ -10,11 +10,18 @@ sql:
|
||||
out: "dbc"
|
||||
emit_pointers_for_null_types: true
|
||||
emit_json_tags: true
|
||||
initialisms: []
|
||||
overrides:
|
||||
- db_type: "timestamptz"
|
||||
go_type:
|
||||
import: "time"
|
||||
type: "Time"
|
||||
- db_type: "timestamptz"
|
||||
nullable: true
|
||||
go_type:
|
||||
import: "time"
|
||||
type: "Time"
|
||||
pointer: true
|
||||
- db_type: "uuid"
|
||||
go_type:
|
||||
import: "github.com/google/uuid"
|
||||
|
@ -49,7 +49,7 @@ type RegisterDto struct {
|
||||
|
||||
func MapDbUser(user *dbc.User) User {
|
||||
return User{
|
||||
Id: user.ID,
|
||||
Id: user.Id,
|
||||
Username: user.Username,
|
||||
Email: user.Email,
|
||||
CreatedDate: user.CreatedDate,
|
||||
@ -84,7 +84,7 @@ func (h *Handler) ListUsers(c echo.Context) error {
|
||||
}
|
||||
users, err = h.db.GetAllUsersAfter(ctx, dbc.GetAllUsersAfterParams{
|
||||
Limit: limit,
|
||||
AfterID: uid,
|
||||
AfterId: uid,
|
||||
})
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user