Reputation: 567
I currently have a directive that I'm using to secure resources in an Akka HTTP app, like so:
def authenticate: Directive1[Login] =
optionalHeaderValueByName("Authorization") flatMap {
val accessToken = authz.split(' ').last
case Some(authz) =>
LoggedInUser findByAccessToken accessToken match {
case Some(user) => provide(user)
case None => reject(AuthorizationFailedRejection)
}
case None => reject(AuthorizationFailedRejection)
}
where LoggedInUser.findByAccessToken()
makes a blocking query against a database, I would like to switch this for an asynchronous ask
to an actor which which can provide the same data, I'm OK with passing in the ActorRef
as a parameter to the directive but I cannot work out how to handle the Future
that the ask returns.
None of the Directive1
examples that come with Akka HTTP seem to do this (at least I could;t find any) although there are examples of directives returning Route
which do.
Is what I want to do even possible? Is a possible approach to create a StandardRoute
subclass with a field for the user credentials and return that somehow?
Upvotes: 15
Views: 3857
Reputation: 8866
Yes, it is possible. As far as I understand you need something like this:
def authenticate: Directive1[Login] = {
def findByAccessToken(accessToken:String): Future[Option[Login]] = ???
optionalHeaderValueByName("Authorization").flatMap {
case Some(authz) =>
val accessToken = authz.split(' ').last
onSuccess(findByAccessToken(accessToken)).flatMap {
case Some(user) => provide(user)
case None => reject(AuthorizationFailedRejection)
}
case None => reject(AuthorizationFailedRejection)
}
}
Upvotes: 23