Ein­füh­rung in OAuth und Streamlit

Will­kom­men zu einer schnel­len Ein­füh­rung in OAuth und Stream­lit, zwei Schlüs­sel­tech­no­lo­gien, die in der moder­nen Web-App-Ent­wick­lung eine große Rolle spielen.

OAuth: Stan­dard für sichere Autorisierung

OAuth ist ein weit ver­brei­te­ter Auto­ri­sie­rungs­stan­dard, der es Anwen­dun­gen erlaubt, auf Dienste im Namen eines Benut­zers zuzu­grei­fen, ohne dass die­ser seine Zugangs­da­ten (wie ein Pass­wort) direkt preis­ge­ben muss. Statt Benut­zer­name und Pass­wort direkt zu ver­wen­den, arbei­tet OAuth mit Tokens, die spe­zi­fi­sche Zugriffs­rechte ver­ge­ben. Diese Methode erhöht die Sicher­heit, da sie den Zugriff auf Benut­zer­da­ten strikt kon­trol­liert und gleich­zei­tig das Risiko eines Pass­wort­dieb­stahls minimiert.

Stream­lit: Leicht­ge­wich­tige Lösun­gen für Web-App-Entwicklung

Stream­lit ist ein Open-Source-Frame­work, das die Ent­wick­lung von Daten- und Ana­lyse-Web-Apps ver­ein­facht. Es ermög­licht Ent­wick­lern, mit weni­gen Zei­len Python-Code visu­ell anspre­chende und inter­ak­tive Web-Apps zu erstel­len. Die Stärke von Stream­lit liegt in sei­ner Ein­fach­heit und der Fähig­keit, schnell Pro­to­ty­pen erstel­len zu kön­nen, ohne sich in die Web­ent­wick­lung ver­tie­fen zu müssen.

Inte­gra­tion von OAuth in Streamlit

Die Kom­bi­na­tion von OAuth mit Stream­lit ermög­licht es, sichere und per­so­na­li­sierte Benut­zer­er­fah­run­gen zu schaf­fen. Durch die Inte­gra­tion von OAuth in eine Stream­lit-App kann der Ent­wick­ler den Benut­zern siche­ren Zugriff auf ihre Daten gewäh­ren und gleich­zei­tig die App um Authen­ti­fi­zie­rungs- und Auto­ri­sie­rungs­funk­tio­nen erwei­tern. Diese Inte­gra­tion bedeu­tet, dass Benut­zer ihre Daten in einer Stream­lit-App sicher nut­zen kön­nen, ohne sen­si­ble Infor­ma­tio­nen preis­zu­ge­ben. Die Inte­gra­tion von OAuth in Stream­lit-Apps stellt einen Schritt dar, um sowohl Sicher­heit als auch Benut­zer­freund­lich­keit zu gewähr­leis­ten. Im Fol­gen­den wer­den wir kon­krete Imple­men­tie­rungs­bei­spiele und Best Prac­ti­ces unter­su­chen, um zu demons­trie­ren, wie Sie diese Tech­no­lo­gien in Ihren eige­nen Pro­jek­ten effek­tiv nut­zen können.

Grund­la­gen der Authen­ti­fi­zie­rung mit Azure und Stream­lit für Entwickler

In die­sem Abschnitt kon­zen­trie­ren wir uns auf die tech­ni­schen Grund­la­gen der Inte­gra­tion von Azure-basier­ter OAuth-Authen­ti­fi­zie­rung in Streamlit-Web-Apps.

Azure Active Direc­tory (Azure AD) bie­tet OAuth 2.0‑Endpunkte, die Sie für die Authen­ti­fi­zie­rung in Ihren Anwen­dun­gen nut­zen kön­nen. Durch die Ver­wen­dung von Azure AD zur Authen­ti­fi­zie­rung kön­nen Ent­wick­ler den Zugriff auf ihre Anwen­dun­gen sicher steu­ern und gleich­zei­tig die Iden­ti­täts­ver­wal­tung und den Schutz sen­si­bler Infor­ma­tio­nen sicherstellen.

Der Authen­ti­fi­zie­rungs­pro­zess mit OAuth 2.0 in Azure AD umfasst meh­rere Schritte:

  1. Anfor­de­rung eines Auto­ri­sie­rungs­codes: Die App lei­tet den Benut­zer zu einem Azure AD-Login-For­mu­lar wei­ter. Nach erfolg­rei­cher Authen­ti­fi­zie­rung wird ein Auto­ri­sie­rungs­to­ken an Ihre App zurückgegeben.
  2. Ein­lö­sen des Auto­ri­sie­rungs­codes: Die App sen­det den erhal­te­nen Auto­ri­sie­rungs­to­ken an Azure AD zurück, um Zugriffsto­kens zu erhalten.
  3. Zugriff auf geschützte Res­sour­cen: Mit dem Zugriffsto­ken kann die App im Namen des Benut­zers auf geschützte Res­sour­cen zugreifen.

Stream­lit-Inte­gra­tion

Stream­lit ermög­licht es Ent­wick­lern, schnell inter­ak­tive Web-Apps für Daten­pro­jekte zu erstel­len. Um OAuth-Authen­ti­fi­zie­rung in eine Stream­lit-App zu inte­grie­ren, müs­sen Sie:

  1. Azure OAuth-Kon­fi­gu­ra­tion vor­be­rei­ten: Regis­trie­ren Sie Ihre Anwen­dung in Azure AD, um die client_id, client_secret und tenant_id zu erhal­ten. Diese Werte sind für die Authen­ti­fi­zie­rung erforderlich.
  2. Authen­ti­fi­zie­rungs-Flow imple­men­tie­ren: Ver­wen­den Sie die erhal­te­nen Kon­fi­gu­ra­ti­ons­werte, um den OAuth-Authen­ti­fi­zie­rungs-Flow in Ihrer Stream­lit-App ein­zu­rich­ten. Dies beinhal­tet zunächst die Erstel­lung eines Login-But­tons, der den Benut­zer zur Azure AD-Anmelde-Seite wei­ter­lei­tet. Anschlie­ßend erfolgt die Ver­ar­bei­tung des Auto­ri­sie­rungs­codes, den Azure AD nach erfolg­rei­cher Anmel­dung zurückgibt.
  3. Zugriffsto­ken nut­zen: Nach­dem Sie den Auto­ri­sie­rungs­to­ken ein­ge­löst haben, erhal­ten Sie ein Zugriffsto­ken. Ver­wen­den Sie die­ses Token, um im Namen des Benut­zers auf geschützte Res­sour­cen zuzugreifen.
  4. Benut­zer­inter­face aktua­li­sie­ren: Inte­grie­ren Sie Logik in Ihre Stream­lit-App, die das Benut­zer­inter­face basie­rend auf dem Authen­ti­fi­zie­rungs­sta­tus aktua­li­siert. Zei­gen Sie bei­spiels­weise bestimmte Infor­ma­tio­nen oder Funk­tio­nen nur authen­ti­fi­zier­ten Benut­zern an.

Best Prac­ti­ces

  • Sicher­heit: Stel­len Sie sicher, dass client_secret und andere sen­si­ble Infor­ma­tio­nen sicher gespei­chert und nicht im Front­end-Code oder in öffent­lich zugäng­li­chen Berei­chen expo­niert werden.
  • Benut­zer­er­fah­rung: Imple­men­tie­ren Sie eine klare und intui­tive Benut­zer­füh­rung durch den Authen­ti­fi­zie­rungs­pro­zess. Stel­len Sie sicher, dass Benut­zer ver­ste­hen, was pas­siert und warum bestimmte Berech­ti­gun­gen erfor­der­lich sind.
  • Feh­ler­be­hand­lung: Ent­wi­ckeln Sie robuste Feh­ler­be­hand­lungs­me­cha­nis­men, um auf Pro­bleme wäh­rend des Authen­ti­fi­zie­rungs­pro­zes­ses ange­mes­sen reagie­ren zu können.

Rol­len­ba­sierte Zugriffs­steue­rung in Stream­lit-Apps mit Azure OAuth

Rol­len­ba­sierte Zugriffs­steue­rung (Role-Based Access Con­trol, RBAC) ist ein ent­schei­den­der Bestand­teil moder­ner Web-Anwen­dun­gen, um sicher­zu­stel­len, dass Benut­zer nur Zugriff auf die für ihre Rolle erfor­der­li­chen Res­sour­cen und Funk­tio­nen haben.

Grund­kon­zept der RBAC

RBAC teilt Benut­zern Rol­len zu, basie­rend auf ihrer Funk­tion inner­halb der Orga­ni­sa­tion oder in der App. Jede Rolle ist mit bestimm­ten Berech­ti­gun­gen ver­bun­den, die den Zugriff auf Res­sour­cen und Aktio­nen in der App steu­ern. Die­ser Ansatz ver­ein­facht die Ver­wal­tung von Berech­ti­gun­gen, da Sie ledig­lich die Rol­len und deren Berech­ti­gun­gen defi­nie­ren und dann Benut­zer die­sen Rol­len zuord­nen müssen.

Imple­men­tie­rung in Azure und Streamlit

  1. Rol­len Defi­ni­tion: Defi­nie­ren Sie die ver­schie­de­nen Benut­zer­rol­len und die zuge­hö­ri­gen Berech­ti­gun­gen in Ihrer Anwen­dung. Dies kann auf ver­schie­dene Arten gesche­hen, bei­spiels­weise durch die Ver­wen­dung einer JSON-Datei, die die Rol­len und ihre Berech­ti­gun­gen abbil­det, oder direkt in Azure AD.
  2. Azure AD Grup­pen: Nut­zen Sie Azure AD Grup­pen, um Benut­zern Rol­len zuzu­wei­sen. Erstel­len Sie für jede Rolle in Ihrer App eine ent­spre­chende Gruppe in Azure AD und fügen Sie Benut­zer zu die­sen Grup­pen hinzu.
  3. Zugriff in Stream­lit steu­ern: Inner­halb Ihrer Stream­lit-App kön­nen Sie die Benut­zer­iden­ti­tät und Grup­pen­mit­glied­schaft prü­fen, um zu bestim­men, wel­che Inhalte und Funk­tio­nen dem Benut­zer ange­zeigt wer­den. Nut­zen Sie das Zugriffsto­ken, das von Azure OAuth bereit­ge­stellt wird, um die Zuge­hö­rig­keit zu Azure AD Grup­pen abzurufen.
  4. Inte­gra­tion in den Authen­ti­fi­zie­rungs­fluss: Inte­grie­ren Sie die Logik zur Über­prü­fung der Benut­zer­rol­len und ‑berech­ti­gun­gen naht­los in den Authen­ti­fi­zie­rungs­pro­zess. Nach­dem ein Benut­zer sich erfolg­reich ange­mel­det hat, prü­fen Sie seine Rolle(n) und pas­sen Sie die Benut­zer­ober­flä­che und den Zugriff ent­spre­chend an.

Best Prac­ti­ces für RBAC mit Azure OAuth in Streamlit

  • Mini­male Berech­ti­gun­gen: Fol­gen Sie dem Prin­zip der mini­ma­len Berech­ti­gun­gen, indem Sie Benut­zern nur die Zugriffs­rechte gewäh­ren, die unbe­dingt für ihre Rolle benö­tigt werden.
  • Dyna­mi­sche Rol­len­prü­fung: Imple­men­tie­ren Sie eine dyna­mi­sche Rol­len­prü­fung, die es ermög­licht, die Rol­len und Berech­ti­gun­gen der Benut­zer bei Bedarf zu aktua­li­sie­ren, ohne die Anwen­dung neu star­ten zu müssen.
  • Sicher­heit und Daten­schutz: Ach­ten Sie dar­auf, dass bei der Imple­men­tie­rung der RBAC und wäh­rend des Authen­ti­fi­zie­rungs­pro­zes­ses die Sicher­heit und der Daten­schutz der Benut­zer­da­ten gewahrt bleiben.
  • Durch die Anwen­dung von RBAC in Ver­bin­dung mit Azure OAuth kön­nen Sie eine siche­rere und benut­zer­freund­li­chere Stream­lit-App erstel­len. Die­ser Ansatz ermög­licht es Ihnen, den Zugriff auf App-Funk­tio­nen prä­zise zu steu­ern und gleich­zei­tig eine ska­lier­bare Lösung für die Zugriffs­ver­wal­tung zu bieten.

Prak­ti­sche Anwen­dung: Inte­gra­tion von Azure OAuth in Streamlit

Die Ein­bin­dung von Azure OAuth in Stream­lit eröff­net Ent­wick­lern die Mög­lich­keit, ihre Web-Apps mit einer robus­ten Authen­ti­fi­zie­rung und rol­len­ba­sier­ten Zugriffs­steue­rung aus­zu­stat­ten. Im Fol­gen­den wird anhand eines Bei­spiels erläu­tert, wie Azure OAuth für die Authen­ti­fi­zie­rung und Auto­ri­sie­rung inner­halb einer Stream­lit-App ver­wen­det wer­den kann.

Ein­rich­tung der Azure_Oauth Klasse

Die Azure_Oauth Klasse bil­det das Herz­stück der Authentifizierung:

class Azure_Oauth:
    def __init__(self, client_id, client_secret, tenant_id, subscriptionId, redirect_uri='http://localhost:8501/'):
        self.client_id = client_id
        self.client_secret = client_secret
        self.tenant_id = tenant_id
        self.subscriptionId = subscriptionId
        self.redirect_uri = redirect_uri
        self.auth_code = None

Diese Klasse initia­li­siert die für die Authen­ti­fi­zie­rung not­wen­di­gen Para­me­ter wie client_id, client_secret, und die tenant_id.

Authen­ti­fi­zie­rungs­link generieren

Die Methode _get_auth_link erstellt den URL-Link zur Anmel­de­seite von Microsoft:

def _get_auth_link(self, scope):
    auth_link = f"https://login.microsoftonline.com/{self.tenant_id}/oauth2/v2.0/authorize?" + f"""
      client_id={self.client_id}&
      response_type=code&
      redirect_uri={urllib.parse.quote(self.redirect_uri, safe="")}&
      scope={urllib.parse.quote(scope[0], safe="")}&
      form_post=query
    """.replace("\n", "").replace(" ", "")
    st_logger.info("Auth link: " + auth_link)
    return auth_link

Anmel­de­but­ton in Stream­lit anzeigen

Mit show_login_button wird ein Anmel­de­but­ton in der Stream­lit-App eingefügt:

def show_login_button(self):
    auth_link = self._get_auth_link(scope=["offline_access https://management.azure.com/.default"])
    button = f"""<a href="{auth_link}" target="_blank">...Sign in with Microsoft...</a>"""
    with st.sidebar:
        st.components.v1.html(button, height=50)

Benut­zer­an­mel­dung verarbeiten

Die Methode logged_in über­prüft, ob der Benut­zer ange­mel­det ist und ver­ar­bei­tet den Anmeldestatus:

def logged_in(self):
    if st.query_params.get("code") is not None:
        self.auth_code = st.query_params.get("code")
        st.query_params.clear()
        st.session_state["userName"], st.session_state["ad_groups"] = self._get_user_information()
    if st.session_state.get("logged_in", False):
        with st.sidebar:
            st.markdown(f"**Logged in as:** {st.session_state['userName']} <br>**Role:** {self.get_role().role_name}", unsafe_allow_html=True)
        return True
    return False

wich­tig ist es, die Infor­ma­tio­nen im Ses­sion State von Stream­lit zu spei­chern, damit die Anwen­dung den Anmel­de­sta­tus des Benut­zers über meh­rere Sei­ten­auf­rufe hin­weg ver­fol­gen kann.

Nut­zung der get_app_access_token Funktion

Die Funk­tion get_app_access_token(scope) ist ent­schei­dend für das Anfor­dern eines Zugriffsto­kens von Azure AD. Das Token wird dann für auto­ri­sierte Anfra­gen an die Micro­soft Graph API oder andere Azure-Dienste ver­wen­det. Der Para­me­ter sco­pes spe­zi­fi­ziert die Zugriffs­be­rech­ti­gun­gen, die die Anwen­dung anfor­dert. Zum Bei­spiel gibt https://graph.microsoft.com/.default der App all­ge­meine Berech­ti­gun­gen zum Zugriff auf Nut­zer­da­ten in Micro­soft Graph.

def get_app_access_token(self, scope):
    if not st.session_state.get("logged_in", False):
        st_logger.error("User not logged in")
        return None
    if scope == st.session_state.get("app_current_scope") and \
       st.session_state.get("app_access_token") is not None:
        return st.session_state["app_access_token"]
    data = {
        "grant_type": "client_credentials",
        "client_id": self.client_id,
        "scope": scope,
        "client_secret": self.client_secret
    }
    response = requests.post(
        f"https://login.microsoftonline.com/{self.tenant_id}/oauth2/v2.0/token", data=data
    )
    st.session_state["app_access_token"] = response.json()["access_token"]
    st.session_state["app_current_scope"] = scope
    return st.session_state["app_access_token"]

get_app_access_token spei­chert das Zugriffsto­ken im Ses­sion State von Stream­lit, um es für spä­tere Anfra­gen zu ver­wen­den, ohne es erneut anfor­dern zu müs­sen. Es kann immer nur ein Scope ange­for­dert wer­den, bei Bedarf muss ein neues Token ange­for­dert werden.

Abru­fen der Azure AD Grup­pen eines Nutzers

Sobald ein gül­ti­ges Zugriffsto­ken vor­liegt, kann es ver­wen­det wer­den, um Anfra­gen an die Micro­soft Graph API zu auto­ri­sie­ren. Ein typi­sches Bei­spiel ist das Abru­fen der Azure AD Grup­pen, denen der Nut­zer ange­hört. Dies ermög­licht es der Anwen­dung, rol­len­ba­sierte Zugriffs­kon­trol­len zu imple­men­tie­ren, indem sie den Zugriff basie­rend auf den Grup­pen­mit­glied­schaf­ten des Nut­zers steuert.

Der fol­gende Code-Schnip­sel illus­triert, wie man die Azure AD Grup­pen des ange­mel­de­ten Nut­zers abruft, indem das Zugriffsto­ken in der Anfrage ver­wen­det wird:

response_json_user_ad_groups = requests.get(
    "https://graph.microsoft.com/v1.0/me/memberOf",
    headers={"Authorization": "Bearer " + token}
)
st.session_state["ad_groups"] = [group["displayName"] for group in response_json_user_ad_groups.json()["value"]]

Diese Methode ermög­licht es der Stream­lit-App, dyna­misch zu reagie­ren und bestimmte Inhalte oder Funk­tio­nen nur Benut­zern inner­halb spe­zi­fi­scher Grup­pen zugäng­lich zu machen.

Rol­len­ba­sierte Zugriffs­steue­rung in Streamlit

Die Rolle des Benut­zers wird mit der Role Klasse definiert:

class Role:
    def __init__(self, role_name: str, ad_group: str, has_access_to_app_resources: bool = False):
        self.role_name = role_name
        self.ad_group = ad_group
        self.has_access_to_app_resources = has_access_to_app_resources

Die Ver­wen­dung die­ser Klasse ermög­licht es, den Zugriff inner­halb der Stream­lit-App basie­rend auf der Benut­zer­rolle zu steuern.

Inte­gra­tion in Streamlit

Zur Nut­zung der Authen­ti­fi­zie­rung in einer Stream­lit-App wird die Azure_Oauth Klasse wie folgt instan­zi­iert und verwendet:

app = Azure_Oauth(client_id, client_secret, tenant_id, subscriptionId, redirect_uri)

if app.logged_in():
    user_role = app.get_role()
    if user_role.has_access_to_app_resources:
        # Hier kann der Code der App stehen, der nur für autorisierte Benutzer zugänglich sein soll
else:
    st.markdown("#### Login required")
    app.show_login_button()

Die­ser Ansatz stellt sicher, dass die Stream­lit-App nur für authen­ti­fi­zierte Benut­zer mit den ent­spre­chen­den Berech­ti­gun­gen zugäng­lich ist.

Die get_role Methode der Azure_Oauth Klasse prüft die Grup­pen­mit­glied­schaft des Benut­zers und ord­net ihm die ent­spre­chende Rolle zu:

def get_role(self):
    if not st.session_state.get("logged_in", False):
        st_logger.error("User not logged in")
        return None
    for role in [Role(**role) for role in self._get_role_dicts()]:
        if role.ad_group in st.session_state["ad_groups"]:
            return role

Die _get_role_dicts Methode lie­fert eine Liste von Rol­len und den zuge­hö­ri­gen Azure AD Grup­pen, die für die Rol­len­mit­glied­schaft erfor­der­lich sind.

Fazit und wei­ter­füh­rende Schritte

Die Inte­gra­tion von Azure OAuth in Stream­lit ermög­licht Ent­wick­lern sichere und per­so­na­li­sierte Web-Anwen­dun­gen mit Azure Active Direc­tory für Authen­ti­fi­zie­rung und Zugriffssteuerung.

Unser Blog beschreibt prä­zise die Schritte zur Imple­men­tie­rung von Azure OAuth in Stream­lit, von der Ein­rich­tung der Azure_Oauth Klasse bis zur Ver­wal­tung von Zugriffsto­kens und rol­len­ba­sier­ter Zugriffs­steue­rung, mit prak­ti­schen Code-Bei­spie­len für jede Phase.

Beson­ders inter­es­sant ist die Nut­zung von Azure AD Grup­pen zur fein­gra­nu­la­ren Kon­trolle über den App-Zugriff, basie­rend auf Benut­zer­rol­len und Gruppenzugehörigkeit.

Für tie­fere Ein­bli­cke bie­ten wir Python-Dateien mit voll­stän­di­gem Inte­gra­ti­ons­code zum Down­load an, die als Aus­gangs­punkt für eigene Anwen­dun­gen dienen.