hiling_go/api/token.go

96 lines
2.2 KiB
Go

package api
import (
"fmt"
"net/http"
"time"
"github.com/gin-gonic/gin"
"github.com/jackc/pgx/v5"
)
type renewAccessRequest struct {
RefreshToken string `json:"refresh_token" binding:"required"`
}
type renewAccessResponse struct {
AccesToken string `json:"access_token"`
AccessTokenExpiresAt time.Time `json:"access_token_expires_at"`
}
func (server *Server) renewAccessToken(ctx *gin.Context) {
var req renewAccessRequest
if err := ctx.ShouldBindJSON(&req); err != nil {
ctx.JSON(http.StatusBadRequest, ErrorResponse(err, ""))
return
}
refreshPayload, err := server.TokenMaker.VerifyToken(req.RefreshToken)
if err != nil {
ctx.JSON(http.StatusUnauthorized, ErrorResponse(err, ""))
return
}
session, err := server.Store.GetSession(ctx, int32(refreshPayload.UserID))
if err != nil {
if err == pgx.ErrNoRows {
ctx.JSON(http.StatusNotFound, ErrorResponse(err, ""))
return
}
ctx.JSON(http.StatusInternalServerError, ErrorResponse(err, ""))
return
}
if session.IsBlocked {
err := fmt.Errorf("blocked session")
ctx.JSON(http.StatusUnauthorized, ErrorResponse(err, ""))
return
}
if session.Username != refreshPayload.Username {
err := fmt.Errorf("incorrect session user")
ctx.JSON(http.StatusUnauthorized, ErrorResponse(err, ""))
return
}
if session.RefreshToken != req.RefreshToken {
err := fmt.Errorf("mismatched session token")
ctx.JSON(http.StatusUnauthorized, ErrorResponse(err, ""))
return
}
if time.Now().After(refreshPayload.ExpiredAt) {
err := fmt.Errorf("expired session")
ctx.JSON(http.StatusUnauthorized, ErrorResponse(err, ""))
return
}
user, err := server.Store.GetUser(ctx, refreshPayload.Username)
if err != nil {
if err == pgx.ErrNoRows {
ctx.JSON(http.StatusNotFound, ErrorResponse(err, ""))
return
}
ctx.JSON(http.StatusInternalServerError, ErrorResponse(err, ""))
return
}
accessToken, accessPayload, err := server.TokenMaker.CreateToken(
refreshPayload.Username,
int(user.ID),
server.Config.TokenDuration,
)
if err != nil {
ctx.JSON(http.StatusInternalServerError, ErrorResponse(err, ""))
return
}
res := renewAccessResponse{
AccesToken: accessToken,
AccessTokenExpiresAt: accessPayload.ExpiredAt,
}
ctx.JSON(http.StatusOK, res)
}