edit study_iuids & accNum in patient jwt to array

This commit is contained in:
mario
2025-05-13 10:07:16 +07:00
parent 2d1f135fda
commit 0d4825d152
7 changed files with 34 additions and 89 deletions

View File

@@ -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",

View File

@@ -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")

View File

@@ -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

View File

@@ -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

View File

@@ -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],
},
})
})

View File

@@ -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
}

View File

@@ -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
}