Description
Avec le Serveur InterSystems IRIS FHIR, vous pouvez construire une stratégie pour personnaliser le comportement du serveur (pour plus de détails, consultez documentation).
Ce référentiel contient une stratégie Python qui peut être utilisée comme point de départ pour construire votre propre stratégie en Python.
Cette stratégie de démonstration présente les caractéristiques suivantes :
- Mettre à jour la déclaration de capacité pour supprimer la ressource
Account
(compte). - Simuler un système de gestion de consentement pour accorder ou non l'accès à la ressource
Observation
.- Si l'utilisateur a des droits suffisants, la ressource
Observation
est renvoyée. - Sinon, la ressource
Observation
n'est pas renvoyée.
- Si l'utilisateur a des droits suffisants, la ressource
Installation
Étapes d'installation
- Clonez le référentiel suivant
git clone git@github.com:grongierisc/iris-fhir-python-strategy.git
- Construisez l'image docker
docker-compose build
- Lancez l'image docker
docker-compose up -d
- Ouvrez le serveur FHIR dans votre navigateur
GET http://localhost:8083/fhir/r4/metadata
Accept: application/json+fhir
La ressource Account
(compte) ne peut pas figurer dans la Déclaration de capacité.
GET http://localhost:8083/fhir/r4/Account
Accept: application/json+fhir
retours :
{
"resourceType": "OperationOutcome",
"issue": [
{
"severity": "error",
"code": "not-supported",
"diagnostics": "<HSFHIRErr>ResourceNotSupported",
"details": {
"text": "Resource type 'Account' is not supported."
}
}
]
}
- Ouvrez le compte d'un patient sans authentification (vous ne devez pas avoir accès à l'Observation)
GET http://localhost:8083/fhir/r4/Observation?patient=178
Content-Type: application/json+fhir
Accept: application/json+fhir
retours :
{
"resourceType": "Bundle",
"id": "feaa09c0-1cb7-11ee-b77a-0242c0a88002",
"type": "searchset",
"timestamp": "2023-07-07T11:07:49Z",
"total": 0,
"link": [
{
"relation": "self",
"url": "http://localhost:8083/fhir/r4/Observation?patient=178"
}
]
}
- Ouvrez le compte d'un patient avec authentification (vous devez avoir accès à l'Observation).
GET http://localhost:8083/fhir/r4/Observation?patient=178
Content-Type: application/json+fhir
Accept: application/json+fhir
Authorization: Basic U3VwZXJVc2VyOlNZUw==
retours :
{
"resourceType": "Bundle",
"id": "953a1b06-1cb7-11ee-b77b-0242c0a88002",
"type": "searchset",
"timestamp": "2023-07-07T11:08:04Z",
"total": 100,
"link": [
{
"relation": "self",
"url": "http://localhost:8083/fhir/r4/Observation?patient=178"
}
],
"entry": [
{
"fullUrl": "http://localhost:8083/fhir/r4/Observation/277",
"resource": {
"resourceType": "Observation",
"id": "277",
"status": "final",
"category": [
...
],
}
},
...
]
}
Vous trouverez plus de détails dans la section suivante "Consentement".
Consentement
Le système de gestion de consentement est simulé par la méthode consent
(consentement) de la classe CustomInteraction
(interaction personnalisée) du module custom
(personnalisation).
La méthode consent
retourne True
(vrai) si l'utilisateur a les droits suffisants pour accéder à la ressource, False
(faux) dans le cas contraire.
def consent(self, resource_type, user, roles):
#Exemple de logique de consentement: autoriser uniquement les utilisateurs ayant le rôle "%All" à consulter
#les ressources "Observation".
if resource_type == 'Observation':
if '%All' in roles:
return True
else:
return False
else:
return True
La fonction consent
fait partie de la classe CustomInteraction
.
La classe CustomInteraction
est une implémentation de la classe Interaction
.
La classe Interaction
est une classe abstraite qui doit être implémentée par la stratégie. Elle fait partie du module FhirInteraction
.
class Interaction(object):
__metaclass__ = abc.ABCMeta
@abc.abstractmethod
def on_before_request(self,
fhir_service:'iris.HS.FHIRServer.API.Service',
fhir_request:'iris.FHIRServer.API.Data.Request',
body:dict,
timeout:int):
"""
on_before_request est appelé avant que la demande ne soit envoyée au serveur.
param fhir_service: objet service fhir iris.HS.FHIRServer.API.Service
param fhir_request: objet service fhir iris.FHIRServer.API.Data.Request
param timeout: le délai en secondes
return: None
"""
@abc.abstractmethod
def on_after_request(self,
fhir_service:'iris.HS.FHIRServer.API.Service',
fhir_request:'iris.FHIRServer.API.Data.Request',
fhir_response:'iris.FHIRServer.API.Data.Response',
body:dict):
"""
on_after_request est appelée après l'envoi de la demande au serveur.
param fhir_service: objet service fhir iris.HS.FHIRServer.API.Service
param fhir_request: objet requête fhir iris.FHIRServer.API.Data.Request
param fhir_response: objet réponse fhir iris.FHIRServer.API.Data.Response
return: None
"""
@abc.abstractmethod
def post_process_read(self,
fhir_object:dict) -> bool:
"""
post_process_read est appelée après l'opération de lecture.
param fhir_object: objet fhir
return: "True" la ressource doit être renvoyée au client, "False" dans le cas contraire
"""
@abc.abstractmethod
def post_process_search(self,
rs:'iris.HS.FHIRServer.Util.SearchResult',
resource_type:str):
"""
post_process_search est appelée une fois l'opération de recherche terminée.
param rs: résultat de recherche iris.HS.FHIRServer.Util.SearchResult
param resource_type: type de ressource
return: None
"""
La classe CustomInteraction
est une implémentation de la classe Interaction
.
class CustomInteraction(Interaction):
def on_before_request(self, fhir_service, fhir_request, body, timeout):
#Extraction de l'utilisateur et des rôles pour cette demande
#afin que le consentement puisse être évalué.
self.requesting_user = fhir_request.Username
self.requesting_roles = fhir_request.Roles
def on_after_request(self, fhir_service, fhir_request, fhir_response, body):
#Suppression de l'utilisateur et des rôles entre les demandes.
self.requesting_user = ""
self.requesting_roles = ""
def post_process_read(self, fhir_object):
#Évaluation du consentement en fonction de la ressource et de l'utilisateur/des rôles.
#La valeur 0 indique que cette ressource ne doit pas être affichée - un message 404 Not Found (404 introuvable)
#sera renvoyé à l'utilisateur.
return self.consent(fhir_object['resourceType'],
self.requesting_user,
self.requesting_roles)
def post_process_search(self, rs, resource_type):
#Itération sur chaque ressource de l'ensemble de recherche et évaluation
#du consentement en fonction de la ressource et de l'utilisateur/des rôles.
#Chaque ligne marquée comme supprimée et sauvegardée sera exclue de l'ensemble.
rs._SetIterator(0)
while rs._Next():
if not self.consent(rs.ResourceType,
self.requesting_user,
self.requesting_roles):
#Sélection de la ligne comme supprimée et sauvegarde.
rs.MarkAsDeleted()
rs._SaveRow()
def consent(self, resource_type, user, roles):
#Exemple de logique de consentement: autoriser uniquement les utilisateurs ayant le rôle "%All" à consulter
#les ressources "Observation".
if resource_type == 'Observation':
if '%All' in roles:
return True
else:
return False
else:
return True
Vous pouvez modifier le module custom
pour implémenter votre propre logique de consentement.
Toutes les modifications apportées au module custom
seront directement reflétées dans le serveur FHIR.
Il est possible d'implémenter d'autres comportements en surchargeant les classes Interaction
.
- WIP
Personnalisation de la ressource CapabilityStatement
Le serveur IRIS FHIR fournit une ressource CapabilityStatement par défaut en fonction du Guide d'implémentation fourni au moment de l'installation.
De plus amples informations sur la manière de personnaliser la Resource CapabilityStatement sont disponibles à l'adresse FHIR CapabilityStatement.
Pour cet exemple, le Guide d'implémentation est FHIR R4 brut.
Pour personnaliser la ressource CapabilityStatement, vous pouvez modifier le module custom
.
La classe CustomStrategy
est une implémentation de la classe Strategy
(stratégie).
La classe Strategy
est une classe abstraite qui doit être implémentée par la stratégie. Elle fait partie du module FhirInteraction
.
class Strategy(object):
__metaclass__ = abc.ABCMeta
@abc.abstractmethod
def on_get_capability_statement(self,capability_statement:dict)-> dict:
"""
on_after_get_capability_statement est appelé une fois la déclaration de capacité récupérée.
param capability_statement: la déclaration de capacité
return: None
"""
La méthode on_get_capability_statement
est appelée après la génération de la ressource CapabilityStatement.
La classe CustomStrategy
est une implémentation de la classe Strategy
.
class CustomStrategy(Strategy):
def on_get_capability_statement(self, capability_statement):
# Exemple : Compte de ressources
capability_statement['rest'][0]['resource'] = [resource for resource in capability_statement['rest'][0]['resource'] if resource['type'] != 'Account']
return capability_statement
Vous pouvez modifier le module custom
pour implémenter votre propre Custom CapabilityStatement.
Pour appliquer les modifications, vous devez mettre à jour la configuration du serveur fhir.
cd /irisdev/app/src/python
/usr/irissys/bin/irispython
>>> import custom
>>> custom.set_capability_statement()