126 lines
3.1 KiB
Go
126 lines
3.1 KiB
Go
package auth
|
|
|
|
import (
|
|
"net/url"
|
|
"strings"
|
|
"time"
|
|
|
|
"server/models"
|
|
authsvc "server/services/auth"
|
|
|
|
beego "github.com/beego/beego/v2/server/web"
|
|
)
|
|
|
|
// AuthSessionController 会话管理(用户自助:查看在线设备、踢下线)
|
|
type AuthSessionController struct {
|
|
beego.Controller
|
|
}
|
|
|
|
func (c *AuthSessionController) serveJSON(data map[string]interface{}) {
|
|
c.Data["json"] = data
|
|
_ = c.ServeJSON()
|
|
}
|
|
|
|
// DevicesPage 在线设备页(浏览器访问,依赖认证中心会话 Cookie)
|
|
// GET /auth/devices
|
|
func (c *AuthSessionController) DevicesPage() {
|
|
sid := strings.TrimSpace(c.Ctx.GetCookie(sessionCookieName))
|
|
if sid == "" {
|
|
c.Redirect("/auth/login", 302)
|
|
return
|
|
}
|
|
session, err := authsvc.GetSession(sid)
|
|
if err != nil {
|
|
c.Redirect("/auth/login", 302)
|
|
return
|
|
}
|
|
|
|
list, err := authsvc.ListActiveSessions(session.IdentityID)
|
|
if err != nil {
|
|
list = nil
|
|
}
|
|
|
|
items := make([]map[string]interface{}, 0, len(list))
|
|
now := time.Now()
|
|
for _, s := range list {
|
|
device := "未知设备"
|
|
if s.DeviceName != nil && strings.TrimSpace(*s.DeviceName) != "" {
|
|
device = *s.DeviceName
|
|
}
|
|
ip := "-"
|
|
if s.IP != nil {
|
|
ip = *s.IP
|
|
}
|
|
client := s.ClientID
|
|
if client == "" {
|
|
client = "-"
|
|
}
|
|
items = append(items, map[string]interface{}{
|
|
"Sid": s.Sid,
|
|
"Current": s.Sid == sid,
|
|
"Device": device,
|
|
"IP": ip,
|
|
"Client": client,
|
|
"LoginAt": s.LoginAt.Format("2006-01-02 15:04"),
|
|
"LastAt": s.LastAccessAt.Format("2006-01-02 15:04"),
|
|
"Expired": s.ExpiresAt.Before(now),
|
|
"Tid": s.Tid,
|
|
})
|
|
}
|
|
|
|
c.Data["Sessions"] = items
|
|
c.Data["Success"] = c.GetString("success")
|
|
c.Data["Error"] = c.GetString("error")
|
|
c.TplName = "auth/devices.tpl"
|
|
}
|
|
|
|
// KickPage 踢下线指定设备(页面入口,踢完后回到设备页)
|
|
// GET /auth/devices/kick?sid=
|
|
func (c *AuthSessionController) KickPage() {
|
|
target := strings.TrimSpace(c.GetString("sid"))
|
|
current := strings.TrimSpace(c.Ctx.GetCookie(sessionCookieName))
|
|
if current == "" {
|
|
c.Redirect("/auth/login", 302)
|
|
return
|
|
}
|
|
session, err := authsvc.GetSession(current)
|
|
if err != nil {
|
|
c.Redirect("/auth/login", 302)
|
|
return
|
|
}
|
|
if target == "" {
|
|
c.Redirect("/auth/devices?error="+url.QueryEscape("参数错误"), 302)
|
|
return
|
|
}
|
|
|
|
// 只允许操作自己名下的会话
|
|
owned := false
|
|
if list, e := authsvc.ListActiveSessions(session.IdentityID); e == nil {
|
|
for _, s := range list {
|
|
if s.Sid == target {
|
|
owned = true
|
|
break
|
|
}
|
|
}
|
|
}
|
|
if !owned {
|
|
c.Redirect("/auth/devices?error="+url.QueryEscape("无权操作该设备"), 302)
|
|
return
|
|
}
|
|
if target == current {
|
|
c.Redirect("/auth/devices?error="+url.QueryEscape("不能踢掉当前设备,请直接登出"), 302)
|
|
return
|
|
}
|
|
|
|
if err := authsvc.RevokeSession(target, models.RevokeReasonAdmin); err != nil {
|
|
c.Redirect("/auth/devices?error="+url.QueryEscape("操作失败"), 302)
|
|
return
|
|
}
|
|
// 同步吊销该会话的刷新令牌,确保对方无法续期
|
|
_, _ = models.Orm.QueryTable(new(models.AuthRefreshToken)).
|
|
Filter("sid", target).
|
|
Update(map[string]interface{}{"revoked": 1})
|
|
|
|
c.Redirect("/auth/devices?success="+url.QueryEscape("已将该设备下线"), 302)
|
|
}
|