From 0d4825d1526e8a3becf210ee3220e511231bb4d0 Mon Sep 17 00:00:00 2001 From: mario Date: Tue, 13 May 2025 10:07:16 +0700 Subject: [PATCH] edit study_iuids & accNum in patient jwt to array --- internal/api/handlers/dicom.go | 24 ++++++--------------- internal/api/middleware/auth.go | 32 +++++++++------------------- internal/api/models/mock_data.go | 12 +++++------ internal/api/models/user.go | 6 ++---- internal/api/routes.go | 4 ++-- internal/api/service/auth_service.go | 27 ++++++----------------- internal/auth/jwt.go | 18 ++-------------- 7 files changed, 34 insertions(+), 89 deletions(-) diff --git a/internal/api/handlers/dicom.go b/internal/api/handlers/dicom.go index 78bdc4a..e3a94ab 100644 --- a/internal/api/handlers/dicom.go +++ b/internal/api/handlers/dicom.go @@ -63,7 +63,7 @@ func (h *DicomHandler) ForwardRequest(w http.ResponseWriter, r *http.Request) { case "patient": // For patients requesting study list, filter to only show their studies if strings.HasPrefix(urlPath, "/studies") && !strings.Contains(urlPath, "/") { - // Check if multiple studies are available in the claim + // Check if studies are available in the claim if len(claims.StudyIUIDs) > 0 { // Remove existing StudyInstanceUID param if it exists queryParams.Del("StudyInstanceUID") @@ -71,12 +71,9 @@ func (h *DicomHandler) ForwardRequest(w http.ResponseWriter, r *http.Request) { // For DICOMweb, we can use comma-separated UIDs queryParams.Set("StudyInstanceUID", strings.Join(claims.StudyIUIDs, ",")) - h.logger.Debug("Filtering by multiple studies", + h.logger.Debug("Filtering by studies", zap.Strings("studies", claims.StudyIUIDs), ) - } else if claims.StudyIUID != "" { - // Fallback for backward compatibility - ensure only the patient's study is shown - queryParams.Set("StudyInstanceUID", claims.StudyIUID) } } else if strings.HasPrefix(urlPath, "/studies/") { // This is a request for a specific study - check if the patient is authorized @@ -90,21 +87,14 @@ func (h *DicomHandler) ForwardRequest(w http.ResponseWriter, r *http.Request) { // Check if this study is in the patient's authorized studies authorized := false - // First check StudyIUIDs array - if len(claims.StudyIUIDs) > 0 { - for _, id := range claims.StudyIUIDs { - if id == studyID { - authorized = true - break - } + // Check StudyIUIDs array + for _, id := range claims.StudyIUIDs { + if id == studyID { + authorized = true + break } } - // Then check single StudyIUID for backward compatibility - if !authorized && claims.StudyIUID == studyID { - authorized = true - } - // If not authorized, return 403 Forbidden if !authorized { h.logger.Warn("Unauthorized study access attempt", diff --git a/internal/api/middleware/auth.go b/internal/api/middleware/auth.go index 79bbbb1..415fa82 100644 --- a/internal/api/middleware/auth.go +++ b/internal/api/middleware/auth.go @@ -187,39 +187,27 @@ func PatientViewRestriction(logger *zap.Logger) func(http.Handler) http.Handler } // If a study is being requested, verify patient has access - if requestedStudyUID != "" { + if requestedStudyUID != "" && len(claims.StudyIUIDs) > 0 { // Check if the requested study is authorized isAuthorized := false - // First check the array of studies if available - if len(claims.StudyIUIDs) > 0 { - for _, studyUID := range claims.StudyIUIDs { - if studyUID == requestedStudyUID { - isAuthorized = true - logger.Debug("Patient authorized to access study from StudyIUIDs array", - zap.String("userID", claims.UserID), - zap.String("requestedStudy", requestedStudyUID)) - break - } + for _, studyUID := range claims.StudyIUIDs { + if studyUID == requestedStudyUID { + isAuthorized = true + logger.Debug("Patient authorized to access study", + zap.String("userID", claims.UserID), + zap.String("requestedStudy", requestedStudyUID)) + break } } - // If not found in the array, check the single StudyIUID for backward compatibility - if !isAuthorized && claims.StudyIUID == requestedStudyUID { - isAuthorized = true - logger.Debug("Patient authorized to access study from StudyIUID", - zap.String("userID", claims.UserID), - zap.String("requestedStudy", requestedStudyUID)) - } - - // If still not authorized, return 403 Forbidden + // If not authorized, return 403 Forbidden if !isAuthorized { logger.Warn("Patient attempted to access unauthorized study", zap.String("userID", claims.UserID), zap.String("role", claims.Role), zap.String("requestedStudy", requestedStudyUID), - zap.Strings("authorizedStudies", claims.StudyIUIDs), - zap.String("authorizedStudy", claims.StudyIUID)) + zap.Strings("authorizedStudies", claims.StudyIUIDs)) // Return 403 Forbidden with a clear message w.Header().Set("Content-Type", "application/json") diff --git a/internal/api/models/mock_data.go b/internal/api/models/mock_data.go index 8914915..903eef9 100644 --- a/internal/api/models/mock_data.go +++ b/internal/api/models/mock_data.go @@ -40,10 +40,8 @@ var MockUsers = []User{ type PatientData struct { PatientID string `json:"patient_id"` UserID string `json:"user_id"` - StudyIUID string `json:"study_iuid,omitempty"` // For backward compatibility - StudyIUIDs []string `json:"study_iuids,omitempty"` // Multiple study IDs - AccessionNumber string `json:"accession_number,omitempty"` // For backward compatibility - AccessionNumbers []string `json:"accession_numbers,omitempty"` // Multiple accession numbers + StudyIUIDs []string `json:"study_iuids"` + AccessionNumbers []string `json:"accession_numbers"` PatientName string `json:"patient_name"` ReferringPhysician string `json:"referring_physician"` } @@ -61,8 +59,8 @@ var MockPatients = []PatientData{ { PatientID: "MR00000359", UserID: "4", - StudyIUID: "1.2.826.0.1.3680043.9.7307.1.202503196393.01", - AccessionNumber: "CR.250319.6393.01", + StudyIUIDs: []string{"1.2.826.0.1.3680043.9.7307.1.202503196393.01"}, + AccessionNumbers: []string{"CR.250319.6393.01"}, PatientName: "Bobon Santoso", ReferringPhysician: "DR. HERWINDO RIDWAN, SP.OT", }, @@ -99,7 +97,7 @@ func FindStudiesByReferringPhysician(physicianName string) []string { var studies []string for _, patient := range MockPatients { if patient.ReferringPhysician == physicianName { - studies = append(studies, patient.StudyIUID) + studies = append(studies, patient.StudyIUIDs...) } } return studies diff --git a/internal/api/models/user.go b/internal/api/models/user.go index e509032..47bad44 100644 --- a/internal/api/models/user.go +++ b/internal/api/models/user.go @@ -25,10 +25,8 @@ type RefreshToken struct { type PatientDetails struct { PatientID string `json:"patient_id"` PatientName string `json:"patient_name"` - AccessionNumber string `json:"accession_number,omitempty"` // For backward compatibility - AccessionNumbers []string `json:"accession_numbers,omitempty"` // Multiple accession numbers - StudyInstanceUID string `json:"study_instance_uid,omitempty"` // For backward compatibility - StudyInstanceUIDs []string `json:"study_instance_uids,omitempty"` // Multiple study IDs + StudyInstanceUIDs []string `json:"study_instance_uids,omitempty"` + AccessionNumbers []string `json:"accession_numbers,omitempty"` } // DoctorDetails contains doctor-specific data diff --git a/internal/api/routes.go b/internal/api/routes.go index 66e237d..11f437e 100644 --- a/internal/api/routes.go +++ b/internal/api/routes.go @@ -158,8 +158,8 @@ func SetupRouter(cfg *config.Config, logger *zap.Logger) http.Handler { }, "patient_info": map[string]string{ "patient_id": claims.PatientID, - "study_iuid": claims.StudyIUID, - "accession_number": claims.AccessionNumber, + "study_iuid": claims.StudyIUIDs[0], + "accession_number": claims.AccessionNumbers[0], }, }) }) diff --git a/internal/api/service/auth_service.go b/internal/api/service/auth_service.go index 4a683c3..5f96ef2 100644 --- a/internal/api/service/auth_service.go +++ b/internal/api/service/auth_service.go @@ -53,26 +53,17 @@ func (s *AuthService) Login(email, password string) (*models.LoginResponse, erro // Set patient-specific claims additionalClaims["patient_id"] = patientData.PatientID additionalClaims["patient_name"] = patientData.PatientName + additionalClaims["study_iuids"] = patientData.StudyIUIDs + additionalClaims["accession_numbers"] = patientData.AccessionNumbers - // Handle multiple studies if available + // For redirectURL and home_url, use first study for simplicity if len(patientData.StudyIUIDs) > 0 { - // Store all studies in the token for DICOMWeb access - additionalClaims["study_iuids"] = patientData.StudyIUIDs - additionalClaims["accession_numbers"] = patientData.AccessionNumbers - - // Set the first study as default for display and backward compatibility - additionalClaims["study_iuid"] = patientData.StudyIUIDs[0] - additionalClaims["accession_number"] = patientData.AccessionNumbers[0] - - // Only use the first study in the redirect URL additionalClaims["home_url"] = fmt.Sprintf("viewer?StudyInstanceUIDs=%s", patientData.StudyIUIDs[0]) redirectURL = fmt.Sprintf("/viewer?StudyInstanceUIDs=%s", patientData.StudyIUIDs[0]) } else { - // Fall back to single study for backward compatibility - additionalClaims["study_iuid"] = patientData.StudyIUID - additionalClaims["accession_number"] = patientData.AccessionNumber - additionalClaims["home_url"] = fmt.Sprintf("viewer?StudyInstanceUIDs=%s", patientData.StudyIUID) - redirectURL = fmt.Sprintf("/viewer?StudyInstanceUIDs=%s", patientData.StudyIUID) + // Fallback for empty studies array (shouldn't happen) + additionalClaims["home_url"] = "/" + redirectURL = "/" } additionalClaims["study_list"] = "disabled" @@ -138,12 +129,6 @@ func (s *AuthService) RefreshToken(refreshToken string) (string, error) { if claims.PatientName != "" { additionalClaims["patient_name"] = claims.PatientName } - if claims.AccessionNumber != "" { - additionalClaims["accession_number"] = claims.AccessionNumber - } - if claims.StudyIUID != "" { - additionalClaims["study_iuid"] = claims.StudyIUID - } if claims.HomeURL != "" { additionalClaims["home_url"] = claims.HomeURL } diff --git a/internal/auth/jwt.go b/internal/auth/jwt.go index e310fd2..747e700 100644 --- a/internal/auth/jwt.go +++ b/internal/auth/jwt.go @@ -40,10 +40,8 @@ type CustomClaims struct { // Patient-specific fields PatientID string `json:"patient_id,omitempty"` PatientName string `json:"patient_name,omitempty"` - AccessionNumber string `json:"accession_number,omitempty"` // For backward compatibility - AccessionNumbers []string `json:"accession_numbers,omitempty"` // Multiple accession numbers - StudyIUID string `json:"study_iuid,omitempty"` // For backward compatibility - StudyIUIDs []string `json:"study_iuids,omitempty"` // Multiple study IUIDs + StudyIUIDs []string `json:"study_iuids,omitempty"` + AccessionNumbers []string `json:"accession_numbers,omitempty"` // Navigation and permissions HomeURL string `json:"home_url,omitempty"` @@ -76,12 +74,6 @@ func (m *JWTManager) GenerateAccessToken(userID, email, role, userName string, a if val, ok := additionalClaims["patient_name"].(string); ok { claims.PatientName = val } - if val, ok := additionalClaims["accession_number"].(string); ok { - claims.AccessionNumber = val - } - if val, ok := additionalClaims["study_iuid"].(string); ok { - claims.StudyIUID = val - } if val, ok := additionalClaims["home_url"].(string); ok { claims.HomeURL = val } @@ -128,12 +120,6 @@ func (m *JWTManager) GenerateRefreshToken(userID, email, role, userName string, if val, ok := additionalClaims["patient_name"].(string); ok { claims.PatientName = val } - if val, ok := additionalClaims["accession_number"].(string); ok { - claims.AccessionNumber = val - } - if val, ok := additionalClaims["study_iuid"].(string); ok { - claims.StudyIUID = val - } if val, ok := additionalClaims["home_url"].(string); ok { claims.HomeURL = val }