@@ -0,0 +1,85 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"gorm.io/gorm"
|
||||
|
||||
"oci-portal/internal/service"
|
||||
)
|
||||
|
||||
// sessionHandler 处理活跃会话查看与定点撤销接口。
|
||||
type sessionHandler struct {
|
||||
auth *service.AuthService
|
||||
}
|
||||
|
||||
// bearerToken 取 Authorization 头中的原始令牌串;不存在返回空串。
|
||||
func bearerToken(c *gin.Context) string {
|
||||
token, ok := strings.CutPrefix(c.GetHeader("Authorization"), "Bearer ")
|
||||
if !ok {
|
||||
return ""
|
||||
}
|
||||
return token
|
||||
}
|
||||
|
||||
// sessionMetaOf 采集会话登记所需的客户端上下文;登录方式由 service 层填写。
|
||||
func sessionMetaOf(c *gin.Context) service.SessionMeta {
|
||||
return service.SessionMeta{
|
||||
ClientIP: requestIP(c),
|
||||
UserAgent: truncateLogField(c.Request.UserAgent(), 256),
|
||||
}
|
||||
}
|
||||
|
||||
// list 列出当前账号的活跃会话,最近活跃在前,当前会话带 current 标记。
|
||||
//
|
||||
// @Summary 活跃会话列表
|
||||
// @Tags 认证
|
||||
// @Success 200 {object} itemsResponse[service.SessionInfo] "items"
|
||||
// @Security BearerAuth
|
||||
// @Router /api/v1/auth/sessions [get]
|
||||
func (h *sessionHandler) list(c *gin.Context) {
|
||||
items, err := h.auth.ListSessions(c.Request.Context(), c.GetString(usernameKey), bearerToken(c))
|
||||
if err != nil {
|
||||
respondError(c, err)
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{"items": items})
|
||||
}
|
||||
|
||||
// revoke 定点撤销一个其他会话;该会话令牌随即失效,不影响其余会话。
|
||||
//
|
||||
// @Summary 撤销单个会话
|
||||
// @Tags 认证
|
||||
// @Param id path int true "会话 ID"
|
||||
// @Success 204 "已撤销"
|
||||
// @Failure 400 {object} errorResponse "id 非法"
|
||||
// @Failure 404 {object} errorResponse "会话不存在"
|
||||
// @Failure 409 {object} errorResponse "不能撤销当前会话"
|
||||
// @Security BearerAuth
|
||||
// @Router /api/v1/auth/sessions/{id} [delete]
|
||||
func (h *sessionHandler) revoke(c *gin.Context) {
|
||||
id, err := strconv.ParseUint(c.Param("id"), 10, 64)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid id"})
|
||||
return
|
||||
}
|
||||
err = h.auth.RevokeSession(c.Request.Context(), c.GetString(usernameKey), bearerToken(c), uint(id))
|
||||
if errors.Is(err, service.ErrSessionCurrent) {
|
||||
c.JSON(http.StatusConflict, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "会话不存在或已失效"})
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
respondError(c, err)
|
||||
return
|
||||
}
|
||||
c.Status(http.StatusNoContent)
|
||||
}
|
||||
Reference in New Issue
Block a user