I am trying to write a custom directive in akka http for something like authorize (with a bit of difference from what’s available OOTB).
object AuthenticationUtils {
def generateUserRequest(implicit system: ActorSystem, executionContext: ExecutionContext): Directive1[UserRequest] = {
optionalHeaderValueByName("Authorization").flatMap {
case Some(tokenValue) if Token.isValidTokenHeader(tokenValue) =>
val token = Token.fromHeader(tokenValue).get
val selection = system.actorSelection("myauthenticator-actor-selection-here")
implicit val timeout: Timeout = Timeout(2 minutes) //may be implicit timeout?
val future = (selection ? RedisTokenActor.GenerateUserRequest(token)).mapTo[GenerateUserRequestResponse]
.map { r => r.optUserRequest}
/*onSuccess(future) { //this does not work.
case Some(ur) => provide(ur)
case _ => reject(AuthorizationFailedRejection)
}*/
val res = Await.result(future, timeout.duration) //todo: make this async.
res match {
case Some(ur) => provide(ur)
case _ => reject(AuthorizationFailedRejection)
}
case _ => reject(AuthorizationFailedRejection)
}
}
}
My question is that, how do I async the execution of the future within a directive? When I use onSuccess, the return objects are not compatible.
Please advice on how do I resolve this. When I use it synchronously, the above code works as desired.
There must still be something wrong, because: future.onSuccess(future) does not make sense.
I have some actor that does some looking up of data source and generates some sort of UserRequest that can be used by some downstream directive (which is sent as part of provide(…)).
The reject directive would fail fast.
This is almost like authorize directive (part of SecurityDirective) with an addition of transforming the token into some sort of business object.
Perhaps your question is more of suggesting a better way of doing this?
And there is a trailing */ in there
Ah… yes. Minus the typo from copying the code, it does work :). Thanks Johanandren!
Another question… how do I have a child directive pass some values back to parent directive?
For example, say I use DebuggingDirectives where I can intercept HttpRequest & Complete/Reject. How could I have some downstream directive like Path to return back some “business context” that can be used by this directive?
for example,
get {
myCustomLogReqResp {
path("some_useful_path") {
//provide some context to logger so that when I send log the req+resp I can also log this context.
complete("some useful response")
}
}
}
the URI from the HttpRequest would be the complete path. In my case, I am looking to intercept the PathMatcher from path directive and get “p1/{IntValue}”.
I was thinking of “writing some mutable object if I cannot directly access the PathMatcher value from myCustomLogReqResp directive and wrap the path directive to intercept the PathMatcher.”… I suppose I m missing something simple :).
But even if I get handle to PathMatcher, is there is an generic extractor that would provide me something like “p1/{IntValue}” so that I may be able to use this logging for any new path directive added?
Is it that you want the directive to extract how much of the path was matched? In the RequestContext you have a unmatchedPath field, that should let you figure that out. I think your directive would have to go inside the path though.