diff --git a/VERSION b/VERSION index 005119b..437459c 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.4.1 +2.5.0 diff --git a/play-life-backend/main.go b/play-life-backend/main.go index 6142348..79d9024 100644 --- a/play-life-backend/main.go +++ b/play-life-backend/main.go @@ -301,7 +301,7 @@ func (a *App) generateAccessToken(userID int) (string, error) { claims := JWTClaims{ UserID: userID, RegisteredClaims: jwt.RegisteredClaims{ - ExpiresAt: jwt.NewNumericDate(time.Now().Add(15 * time.Minute)), + ExpiresAt: jwt.NewNumericDate(time.Now().Add(24 * time.Hour)), IssuedAt: jwt.NewNumericDate(time.Now()), }, } @@ -460,7 +460,7 @@ func (a *App) registerHandler(w http.ResponseWriter, r *http.Request) { _, err = a.DB.Exec(` INSERT INTO refresh_tokens (user_id, token_hash, expires_at) VALUES ($1, $2, $3) - `, user.ID, refreshTokenHash, time.Now().Add(7*24*time.Hour)) + `, user.ID, refreshTokenHash, nil) if err != nil { log.Printf("Error storing refresh token: %v", err) } @@ -472,7 +472,7 @@ func (a *App) registerHandler(w http.ResponseWriter, r *http.Request) { json.NewEncoder(w).Encode(TokenResponse{ AccessToken: accessToken, RefreshToken: refreshToken, - ExpiresIn: 900, // 15 minutes + ExpiresIn: 86400, // 24 hours User: user, }) } @@ -567,7 +567,7 @@ func (a *App) loginHandler(w http.ResponseWriter, r *http.Request) { _, err = a.DB.Exec(` INSERT INTO refresh_tokens (user_id, token_hash, expires_at) VALUES ($1, $2, $3) - `, user.ID, refreshTokenHash, time.Now().Add(7*24*time.Hour)) + `, user.ID, refreshTokenHash, nil) if err != nil { log.Printf("Error storing refresh token: %v", err) } @@ -579,7 +579,7 @@ func (a *App) loginHandler(w http.ResponseWriter, r *http.Request) { json.NewEncoder(w).Encode(TokenResponse{ AccessToken: accessToken, RefreshToken: refreshToken, - ExpiresIn: 900, + ExpiresIn: 86400, // 24 hours User: user, }) } @@ -603,12 +603,12 @@ func (a *App) refreshTokenHandler(w http.ResponseWriter, r *http.Request) { return } - // Find valid refresh token + // Find valid refresh token (expires_at is NULL for tokens without expiration) rows, err := a.DB.Query(` SELECT rt.id, rt.user_id, rt.token_hash, u.email, u.name, u.created_at, u.updated_at, u.is_active, u.last_login_at FROM refresh_tokens rt JOIN users u ON rt.user_id = u.id - WHERE rt.expires_at > NOW() + WHERE rt.expires_at IS NULL OR rt.expires_at > NOW() `) if err != nil { log.Printf("Error querying refresh tokens: %v", err) @@ -669,13 +669,13 @@ func (a *App) refreshTokenHandler(w http.ResponseWriter, r *http.Request) { a.DB.Exec(` INSERT INTO refresh_tokens (user_id, token_hash, expires_at) VALUES ($1, $2, $3) - `, user.ID, refreshTokenHash, time.Now().Add(7*24*time.Hour)) + `, user.ID, refreshTokenHash, nil) w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(TokenResponse{ AccessToken: accessToken, RefreshToken: refreshToken, - ExpiresIn: 900, + ExpiresIn: 86400, // 24 hours User: user, }) } @@ -2568,8 +2568,8 @@ func (a *App) initAuthDB() error { // Не возвращаем ошибку, чтобы приложение могло запуститься } - // Clean up expired refresh tokens - a.DB.Exec("DELETE FROM refresh_tokens WHERE expires_at < NOW()") + // Clean up expired refresh tokens (only those with expiration date set) + a.DB.Exec("DELETE FROM refresh_tokens WHERE expires_at IS NOT NULL AND expires_at < NOW()") return nil } diff --git a/play-life-backend/migrations/014_make_refresh_tokens_permanent.sql b/play-life-backend/migrations/014_make_refresh_tokens_permanent.sql new file mode 100644 index 0000000..f4e2530 --- /dev/null +++ b/play-life-backend/migrations/014_make_refresh_tokens_permanent.sql @@ -0,0 +1,21 @@ +-- Migration: Make refresh tokens permanent (no expiration) +-- Refresh tokens теперь не имеют срока действия (expires_at может быть NULL) +-- Access tokens живут 24 часа вместо 15 минут + +-- ============================================ +-- 1. Изменяем expires_at на NULLABLE +-- ============================================ +ALTER TABLE refresh_tokens +ALTER COLUMN expires_at DROP NOT NULL; + +-- ============================================ +-- 2. Устанавливаем NULL для всех существующих токенов +-- (или можно оставить их как есть, если они еще не истекли) +-- ============================================ +-- UPDATE refresh_tokens SET expires_at = NULL WHERE expires_at > NOW(); + +-- ============================================ +-- 3. Комментарий +-- ============================================ +COMMENT ON COLUMN refresh_tokens.expires_at IS 'Expiration date for refresh token. NULL means token never expires.'; +