feat: implement precise token logout

This commit is contained in:
richjohnrambo
2026-09-10 09:43:02 +08:00
parent 98234db263
commit 6b2f1e06e0
8 changed files with 107 additions and 15 deletions
+31 -4
View File
@@ -6677,14 +6677,19 @@ func authenticateIMHTTPBearer(wrt http.ResponseWriter, req *http.Request) (*imPr
}
func resolveIMHTTPBearer(req *http.Request) (*imPrincipal, error) {
principal, _, _, err := resolveIMHTTPBearerToken(req)
return principal, err
}
func resolveIMHTTPBearerToken(req *http.Request) (*imPrincipal, []byte, time.Duration, error) {
authz := strings.TrimSpace(req.Header.Get("Authorization"))
token, ok := strings.CutPrefix(authz, "Bearer ")
if !ok || strings.TrimSpace(token) == "" || store.Store == nil {
return nil, types.ErrPermissionDenied
return nil, nil, 0, types.ErrPermissionDenied
}
handler := store.Store.GetLogicalAuthHandler("token")
if handler == nil || !handler.IsInitialized() {
return nil, types.ErrUnsupported
return nil, nil, 0, types.ErrUnsupported
}
secret := []byte(strings.TrimSpace(token))
if decoded, err := base64.StdEncoding.DecodeString(strings.TrimSpace(token)); err == nil {
@@ -6692,9 +6697,31 @@ func resolveIMHTTPBearer(req *http.Request) (*imPrincipal, error) {
}
rec, _, err := handler.Authenticate(auth.AuthContext{}, secret)
if err != nil || rec == nil || rec.TenantID.IsZero() || rec.Uid.IsZero() {
return nil, types.ErrPermissionDenied
return nil, nil, 0, types.ErrPermissionDenied
}
return &imPrincipal{TenantID: rec.TenantID, Uid: rec.Uid}, nil
return &imPrincipal{TenantID: rec.TenantID, Uid: rec.Uid}, secret, time.Duration(rec.Lifetime), nil
}
func serveIMAuthLogout(wrt http.ResponseWriter, req *http.Request) {
if req.Method != http.MethodPost {
writeIMError(wrt, req, http.StatusMethodNotAllowed, 30000, imReasonMethodNotAllowed, "method not allowed", nil)
return
}
principal, token, ttl, err := resolveIMHTTPBearerToken(req)
if err != nil {
writeIMError(wrt, req, http.StatusUnauthorized, 30043, imReasonAuthRequired, "authentication required", nil)
return
}
if ttl < time.Second {
ttl = time.Second
}
enabled, err := store.RevokeLoginToken(principal.TenantID, token, ttl)
if err != nil || !enabled {
logs.Warn.Println("im logout: token revocation failed", principal.TenantID, principal.Uid, err)
writeIMError(wrt, req, http.StatusInternalServerError, 90000, imReasonInternal, "internal error", nil)
return
}
writeIMSuccess(wrt, req, map[string]any{"status": "ok"})
}
func currentUserPhone(tenantID types.TenantID, uid types.Uid) (string, error) {