2017-02-14 2 views
0

Ich habe einfach Twisted-Klein Server mit HTTP Basic Auth global aktiviert deaktivieren:Wie HTTP Basic Auth für bestimmte API-Endpunkte auf Twisted Klein Server

from klein import Klein 
import attr 
from zope.interface import implementer 
from twisted.cred.portal import IRealm 
from twisted.internet.defer import succeed 
from twisted.cred.portal import Portal 
from twisted.cred.checkers import FilePasswordDB 
from twisted.web.resource import IResource 
from twisted.web.guard import HTTPAuthSessionWrapper, BasicCredentialFactory 
from werkzeug.datastructures import MultiDict 
from bson import json_util 
import json 


app = Klein() 


# health check 
@app.route('/health', methods=['GET']) 
def health_check(request): 
    return '' 


# dataset query API 
@app.route('/query/<path:expression>', methods=['GET']) 
def query(request, expression): 
    response = evaluate_expression(expression) 
    return response 


@implementer(IRealm) 
@attr.s 
class HTTPAuthRealm(object): 
    resource = attr.ib() 

    def requestAvatar(self, avatarId, mind, *interfaces): 
     return succeed((IResource, self.resource, lambda: None)) 


def resource(): 
    realm = HTTPAuthRealm(resource=app.resource()) 
    portal = Portal(realm, [FilePasswordDB('./configs/server-auth.db')]) 
    credential_factory = BasicCredentialFactory('Authentication required') 
    return HTTPAuthSessionWrapper(portal, [credential_factory]) 

Ich möchte deaktivieren Auth nur für bestimmte API-Endpunkte, für Beispiel, in diesem Fall für API-Endpunkt. Ich habe die Dokumentation gelesen, aber ich kann mich nicht darum kümmern.

Antwort

2

Eine Möglichkeit ist, nur den Teil der Hierarchie wickeln, die Sie die Authentifizierung für wollen:

from twisted.web.resource import Resource 

class Health(Resource): 
    # ... 

def resource(): 
    realm = HTTPAuthRealm(resource=app.resource()) 
    portal = Portal(realm, [FilePasswordDB('./configs/server-auth.db')]) 
    credential_factory = BasicCredentialFactory('Authentication required') 
    guarded = HTTPAuthSessionWrapper(portal, [credential_factory]) 

    root = Resource() 
    root.putChild(b"health", Health()) 
    root.putChild(b"this-stuff-requires-auth", guarded) 

    return root 

Die normale Ressource-Traversal-Logik verwendet, um Anforderungen für den Versand an root beginnen. Wenn die Anforderung für /health (oder ein beliebiges Kind) lautet, wird roothealth untergeordnet. Dies ist die Health Instanz, die in diesem Beispiel erstellt wurde. Beachten Sie, wie sich die HTTPAuthSessionWrapper dort nicht beteiligt. Wenn die Anforderung für /this-stuff-requires-auth (oder ein beliebiges untergeordnetes Element) lautet, wird traversal durchlaufen den Authentifizierungswrapper und Authentifizierung ist erforderlich.

Ein anderer Ansatz besteht darin, Ihren Avatar basierend auf den Anmeldeinformationen zu variieren. In diesem Schema authentifizieren Sie tatsächlich alle Benutzer, aber Sie erlauben anonymen Benutzern den Zugriff auf einige der Hierarchie.

from twisted.cred.checkers import ANONYMOUS 

@implementer(IRealm) 
@attr.s 
class HTTPAuthRealm(object): 
    def requestAvatar(self, avatarId, mind, *interfaces): 
     avatar = Resource() 
     avatar.putChild(b"health", Health()) 
     if avatarId is not ANONYMOUS: 
      avatar.putChild(b"this-stuff-requires-auth", SecretResource()) 
     return succeed((IResource, avatar, lambda: None)) 

Sie werden auch Ihr Portal mit Anmeldeinformationen konfigurieren müssen checker für anonyme Anmeldeinformationen:

from twisted.cred.checkers import AllowAnonymousAccess 

portal = Portal(
    realm, [ 
     FilePasswordDB('./configs/server-auth.db'), 
     AllowAnonymousAccess(), 
    ], 
) 

Bei diesem Ansatz HTTPAuthSessionWrapper wieder Ressource Ihre Wurzel ist.

Anonyme Anfragen sind mit der Avatar-ID ANONYMOUS verbunden und HTTPAuthRealm gibt eine IResource zurück, die nur über die Ressourcen weiß, die anonymen Benutzern zur Verfügung stehen sollten.

Anfragen mit gültigen Benutzeranmeldeinformationen sind mit einer anderen Avatarkennung (normalerweise ihrem Benutzernamen) verknüpft und HTTPAuthRealm gibt eine IResource zurück, an die mehr Kinder angehängt sind, wodurch mehr Zugriff gewährt wird.

+0

Danke! Das funktioniert! Wenn ich keinen Pre-Path für meine Authentifizierungs-APIs haben möchte, wie würde ich das tun? Ich habe versucht, etwas wie: 'root.putChild (b '', bewacht) ', aber ich bekomme' 404 keine solche Ressource' Fehler, wenn ich versuche, die APIs abzufragen. –

+0

Es gibt eine Möglichkeit zu tun, was Sie wollen. Sie müssen das Ergebnis von 'requestAvatar' anpassen, anstatt an der Ressourcenhierarchie zu arbeiten, die HTTPAuthSessionWrapper enthält. Ich habe nicht das Gefühl, jetzt ein vollständiges Beispiel zu schreiben, möglicherweise später. –

+0

Ok danke. Ich würde mich freuen, wenn Sie mir ein Beispiel dafür zeigen können. –