| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163 |
- package auth
- import (
- "errors"
- "net/http"
- "time"
- "github.com/gin-gonic/gin"
- )
- // 会话、授信设备、Token 的 handler,对照 docs/api.md 第三、四、五节。
- // 这三个资源都只允许会话身份操作(Token 一律 403),在路由层挂 RequireSession。
- type listResponse struct {
- Items any `json:"items"`
- Total int `json:"total"`
- }
- // ListSessions 实现 GET /api/sessions(api.md 3.1)。
- func (h *Handler) ListSessions(c *gin.Context) {
- items, err := h.svc.ListSessions(c.Request.Context(), UserID(c), SessionID(c))
- if err != nil {
- InternalError(c, err)
- return
- }
- c.JSON(http.StatusOK, listResponse{Items: items, Total: len(items)})
- }
- // DeleteSession 实现 DELETE /api/sessions/:id(api.md 3.2)。
- func (h *Handler) DeleteSession(c *gin.Context) {
- id := c.Param("id")
- createdAt, err := h.svc.FindSessionOwner(c.Request.Context(), UserID(c), id)
- if err != nil {
- if errors.Is(err, ErrSessionNotFound) {
- NotFound(c)
- return
- }
- InternalError(c, err)
- return
- }
- err = h.svc.RevokeSession(c.Request.Context(), UserID(c), id, SessionID(c))
- if err != nil {
- switch {
- case errors.Is(err, ErrCannotRevokeCurrentSession):
- ValidationFailed(c, map[string]string{"id": ErrCannotRevokeCurrentSession.Error()})
- case errors.Is(err, ErrSessionNotFound):
- NotFound(c)
- default:
- InternalError(c, err)
- }
- return
- }
- if h.OnSessionRevoked != nil {
- h.OnSessionRevoked(c, h.auditContext(c), id, createdAt.Format(time.RFC3339))
- }
- c.Status(http.StatusNoContent)
- }
- // ListTrustedDevices 实现 GET /api/trusted-devices(api.md 4.1)。
- func (h *Handler) ListTrustedDevices(c *gin.Context) {
- items, err := h.svc.ListTrustedDevices(c.Request.Context(), UserID(c))
- if err != nil {
- InternalError(c, err)
- return
- }
- c.JSON(http.StatusOK, listResponse{Items: items, Total: len(items)})
- }
- // DeleteTrustedDevice 实现 DELETE /api/trusted-devices/:id(api.md 4.2)。
- func (h *Handler) DeleteTrustedDevice(c *gin.Context) {
- id := c.Param("id")
- device, err := h.svc.FindTrustedDevice(c.Request.Context(), UserID(c), id)
- if err != nil {
- if errors.Is(err, ErrTrustedDeviceNotFound) {
- NotFound(c)
- return
- }
- InternalError(c, err)
- return
- }
- if err := h.svc.RevokeTrustedDevice(c.Request.Context(), UserID(c), id); err != nil {
- if errors.Is(err, ErrTrustedDeviceNotFound) {
- NotFound(c)
- return
- }
- InternalError(c, err)
- return
- }
- if h.OnDeviceRevoked != nil {
- h.OnDeviceRevoked(c, h.auditContext(c), device.DeviceName)
- }
- c.Status(http.StatusNoContent)
- }
- // ListTokens 实现 GET /api/tokens(api.md 5.1)。
- func (h *Handler) ListTokens(c *gin.Context) {
- items, err := h.svc.ListAPITokens(c.Request.Context(), UserID(c))
- if err != nil {
- InternalError(c, err)
- return
- }
- c.JSON(http.StatusOK, listResponse{Items: items, Total: len(items)})
- }
- type createTokenRequest struct {
- Name string `json:"name" binding:"required"`
- Scope string `json:"scope" binding:"required"`
- ExpiresAt *time.Time `json:"expires_at"`
- }
- // CreateToken 实现 POST /api/tokens(api.md 5.2)。
- func (h *Handler) CreateToken(c *gin.Context) {
- var req createTokenRequest
- if !bind(c, &req) {
- return
- }
- if err := ValidateScope(req.Scope); err != nil {
- ValidationFailed(c, map[string]string{"scope": err.Error()})
- return
- }
- created, err := h.svc.CreateAPIToken(c.Request.Context(), UserID(c), req.Name, req.Scope, req.ExpiresAt)
- if err != nil {
- InternalError(c, err)
- return
- }
- if h.OnTokenCreated != nil {
- h.OnTokenCreated(c, h.auditContext(c), created.Name, created.Scope, created.TokenPrefix)
- }
- // 明文只在这里返回一次(api.md 5.2 / auth.md 第五节规则 1)
- c.JSON(http.StatusCreated, created)
- }
- // DeleteToken 实现 DELETE /api/tokens/:id(api.md 5.3)。
- func (h *Handler) DeleteToken(c *gin.Context) {
- id := c.Param("id")
- token, err := h.svc.RevokeAPIToken(c.Request.Context(), UserID(c), id)
- if err != nil {
- switch {
- case errors.Is(err, ErrTokenNotFound):
- NotFound(c)
- case errors.Is(err, ErrTokenAlreadyRevoked):
- ValidationFailed(c, map[string]string{"id": ErrTokenAlreadyRevoked.Error()})
- default:
- InternalError(c, err)
- }
- return
- }
- if h.OnTokenRevoked != nil {
- h.OnTokenRevoked(c, h.auditContext(c), token.Name, token.TokenPrefix)
- }
- c.Status(http.StatusNoContent)
- }
|