162 lines
3.9 KiB
Go
162 lines
3.9 KiB
Go
package controller
|
|
|
|
import (
|
|
"net/http"
|
|
|
|
"metazone.cc/mce/internal/common"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
// ListSessions 列出当前用户的所有活跃会话
|
|
func (sc *SettingsController) ListSessions(c *gin.Context) {
|
|
uid, exists := c.Get("uid")
|
|
if !exists {
|
|
common.Error(c, http.StatusUnauthorized, "请先登录")
|
|
return
|
|
}
|
|
|
|
sessions, err := sc.sessionMgr.ListByUID(uid.(uint))
|
|
if err != nil {
|
|
common.Error(c, http.StatusInternalServerError, "查询失败")
|
|
return
|
|
}
|
|
|
|
currentSID, _ := c.Cookie(common.SessionCookieName)
|
|
|
|
type sessionItem struct {
|
|
ID string `json:"id"`
|
|
IP string `json:"ip"`
|
|
UserAgent string `json:"user_agent"`
|
|
Remark string `json:"remark"`
|
|
RememberMe bool `json:"remember_me"`
|
|
CreatedAt string `json:"created_at"`
|
|
LastAccess string `json:"last_access"`
|
|
IsCurrent bool `json:"is_current"`
|
|
}
|
|
|
|
var items []sessionItem
|
|
for _, s := range sessions {
|
|
items = append(items, sessionItem{
|
|
ID: s.ID,
|
|
IP: s.IP,
|
|
UserAgent: s.UserAgent,
|
|
Remark: s.Remark,
|
|
RememberMe: s.RememberMe,
|
|
CreatedAt: s.CreatedAt.Format("2006-01-02 15:04:05"),
|
|
LastAccess: s.LastAccess.Format("2006-01-02 15:04:05"),
|
|
IsCurrent: s.ID == currentSID,
|
|
})
|
|
}
|
|
if items == nil {
|
|
items = []sessionItem{}
|
|
}
|
|
|
|
common.Ok(c, gin.H{"sessions": items})
|
|
}
|
|
|
|
// DestroySession 踢出指定会话(需验证归属当前用户)
|
|
func (sc *SettingsController) DestroySession(c *gin.Context) {
|
|
uid, exists := c.Get("uid")
|
|
if !exists {
|
|
common.Error(c, http.StatusUnauthorized, "请先登录")
|
|
return
|
|
}
|
|
|
|
sid := c.Param("sid")
|
|
if sid == "" {
|
|
common.Error(c, http.StatusBadRequest, "缺少会话 ID")
|
|
return
|
|
}
|
|
|
|
// 验证目标会话属于当前用户
|
|
sessions, err := sc.sessionMgr.ListByUID(uid.(uint))
|
|
if err != nil {
|
|
common.Error(c, http.StatusInternalServerError, "操作失败")
|
|
return
|
|
}
|
|
found := false
|
|
for _, s := range sessions {
|
|
if s.ID == sid {
|
|
found = true
|
|
break
|
|
}
|
|
}
|
|
if !found {
|
|
common.Error(c, http.StatusNotFound, "会话不存在")
|
|
return
|
|
}
|
|
|
|
// 不能踢出当前会话
|
|
currentSID, _ := c.Cookie(common.SessionCookieName)
|
|
if sid == currentSID {
|
|
common.Error(c, http.StatusBadRequest, "不能踢出当前设备,请使用退出登录")
|
|
return
|
|
}
|
|
|
|
if err := sc.sessionMgr.Destroy(sid); err != nil {
|
|
common.Error(c, http.StatusInternalServerError, "操作失败")
|
|
return
|
|
}
|
|
|
|
common.OkMessage(c, "已踢出该设备")
|
|
}
|
|
|
|
// DestroyOtherSessions 一键踢出非当前设备的所有会话
|
|
func (sc *SettingsController) DestroyOtherSessions(c *gin.Context) {
|
|
uid, exists := c.Get("uid")
|
|
if !exists {
|
|
common.Error(c, http.StatusUnauthorized, "请先登录")
|
|
return
|
|
}
|
|
|
|
currentSID, _ := c.Cookie(common.SessionCookieName)
|
|
if currentSID == "" {
|
|
common.Error(c, http.StatusBadRequest, "无法识别当前会话")
|
|
return
|
|
}
|
|
|
|
if err := sc.sessionMgr.DestroyOtherByUID(uid.(uint), currentSID); err != nil {
|
|
common.Error(c, http.StatusInternalServerError, "操作失败")
|
|
return
|
|
}
|
|
|
|
common.OkMessage(c, "已踢出所有其他设备")
|
|
}
|
|
|
|
// UpdateSessionRemark 更新指定会话的备注
|
|
func (sc *SettingsController) UpdateSessionRemark(c *gin.Context) {
|
|
uid, exists := c.Get("uid")
|
|
if !exists {
|
|
common.Error(c, http.StatusUnauthorized, "请先登录")
|
|
return
|
|
}
|
|
|
|
sid := c.Param("sid")
|
|
if sid == "" {
|
|
common.Error(c, http.StatusBadRequest, "缺少会话 ID")
|
|
return
|
|
}
|
|
|
|
var req struct {
|
|
Remark string `json:"remark"`
|
|
}
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
common.Error(c, http.StatusBadRequest, "请检查输入")
|
|
return
|
|
}
|
|
|
|
// 备注长度限制
|
|
if len(req.Remark) > 32 {
|
|
common.Error(c, http.StatusBadRequest, "备注不能超过 32 个字符")
|
|
return
|
|
}
|
|
|
|
if err := sc.sessionMgr.UpdateRemark(sid, uid.(uint), req.Remark); err != nil {
|
|
common.Error(c, http.StatusInternalServerError, "操作失败")
|
|
return
|
|
}
|
|
|
|
common.OkMessage(c, "备注已更新")
|
|
}
|