mirror of
https://github.com/AlistGo/alist.git
synced 2025-11-25 03:15:10 +08:00
* feat(auth): Enhanced device login session management - Upon login, obtain and verify `Client-Id` to ensure unique device sessions. - If there are too many device sessions, clean up old ones according to the configured policy or return an error. - If a device session is invalid, deregister the old token and return a 401 error. - Added `EnsureActiveOnLogin` function to handle the creation and refresh of device sessions during login. * feat(session): Modified session deletion logic to mark sessions as inactive. - Changed session deletion logic to mark sessions as inactive using the `MarkInactive` method. - Adjusted error handling to ensure an error is returned if marking fails. * feat(session): Added device limits and eviction policies - Added a device limit, controlling the maximum number of devices using the `MaxDevices` configuration option. - If the number of devices exceeds the limit, the configured eviction policy is used. - If the policy is `evict_oldest`, the oldest device is evicted. - Otherwise, an error message indicating too many devices is returned. * refactor(session): Filter for the user's oldest active session - Renamed `GetOldestSession` to `GetOldestActiveSession` to more accurately reflect its functionality - Updated the SQL query to add the `status = SessionActive` condition to retrieve only active sessions - Replaced all callpoints and unified the new function name to ensure logical consistency
70 lines
2.6 KiB
Go
70 lines
2.6 KiB
Go
package db
|
|
|
|
import (
|
|
"github.com/alist-org/alist/v3/internal/model"
|
|
"github.com/pkg/errors"
|
|
"gorm.io/gorm/clause"
|
|
)
|
|
|
|
func GetSession(userID uint, deviceKey string) (*model.Session, error) {
|
|
s := model.Session{UserID: userID, DeviceKey: deviceKey}
|
|
if err := db.Select("user_id, device_key, last_active, status, user_agent, ip").Where(&s).First(&s).Error; err != nil {
|
|
return nil, errors.Wrap(err, "failed find session")
|
|
}
|
|
return &s, nil
|
|
}
|
|
|
|
func CreateSession(s *model.Session) error {
|
|
return errors.WithStack(db.Create(s).Error)
|
|
}
|
|
|
|
func UpsertSession(s *model.Session) error {
|
|
return errors.WithStack(db.Clauses(clause.OnConflict{UpdateAll: true}).Create(s).Error)
|
|
}
|
|
|
|
func DeleteSession(userID uint, deviceKey string) error {
|
|
return errors.WithStack(db.Where("user_id = ? AND device_key = ?", userID, deviceKey).Delete(&model.Session{}).Error)
|
|
}
|
|
|
|
func CountActiveSessionsByUser(userID uint) (int64, error) {
|
|
var count int64
|
|
err := db.Model(&model.Session{}).
|
|
Where("user_id = ? AND status = ?", userID, model.SessionActive).
|
|
Count(&count).Error
|
|
return count, errors.WithStack(err)
|
|
}
|
|
|
|
func DeleteSessionsBefore(ts int64) error {
|
|
return errors.WithStack(db.Where("last_active < ?", ts).Delete(&model.Session{}).Error)
|
|
}
|
|
|
|
// GetOldestActiveSession returns the oldest active session for the specified user.
|
|
func GetOldestActiveSession(userID uint) (*model.Session, error) {
|
|
var s model.Session
|
|
if err := db.Where("user_id = ? AND status = ?", userID, model.SessionActive).
|
|
Order("last_active ASC").First(&s).Error; err != nil {
|
|
return nil, errors.Wrap(err, "failed get oldest active session")
|
|
}
|
|
return &s, nil
|
|
}
|
|
|
|
func UpdateSessionLastActive(userID uint, deviceKey string, lastActive int64) error {
|
|
return errors.WithStack(db.Model(&model.Session{}).Where("user_id = ? AND device_key = ?", userID, deviceKey).Update("last_active", lastActive).Error)
|
|
}
|
|
|
|
func ListSessionsByUser(userID uint) ([]model.Session, error) {
|
|
var sessions []model.Session
|
|
err := db.Select("user_id, device_key, last_active, status, user_agent, ip").Where("user_id = ? AND status = ?", userID, model.SessionActive).Find(&sessions).Error
|
|
return sessions, errors.WithStack(err)
|
|
}
|
|
|
|
func ListSessions() ([]model.Session, error) {
|
|
var sessions []model.Session
|
|
err := db.Select("user_id, device_key, last_active, status, user_agent, ip").Where("status = ?", model.SessionActive).Find(&sessions).Error
|
|
return sessions, errors.WithStack(err)
|
|
}
|
|
|
|
func MarkInactive(sessionID string) error {
|
|
return errors.WithStack(db.Model(&model.Session{}).Where("device_key = ?", sessionID).Update("status", model.SessionInactive).Error)
|
|
}
|