authorizeAsync
Applies the given authorization check to the request.
Signature
def authorizeAsync(check: => Future[Boolean]): Directive0
def authorizeAsync(check: RequestContext => Future[Boolean]): Directive0
Description
The user-defined authorization check can either be supplied as a => Future[Boolean]
Supplier<CompletionStage<Boolean>>
value which is calculated just from information out of the lexical scope, or as a function RequestContext => Future[Boolean]
Function<RequestContext,CompletionStage<Boolean>>
which can also take information from the request itself into account.
If the check returns true
, the request is passed on to the inner route unchanged; if it returns false
or the Future
CompletionStage
is failed, an AuthorizationFailedRejection
AuthorizationFailedRejection
is created, triggering a 403 Forbidden
response by default (the same as in the case of an AuthenticationFailedRejection
AuthenticationFailedRejection
).
In a common use-case you would check if a user (e.g. supplied by any of the authenticate*
family of directives, e.g. authenticateBasic) is allowed to access the inner routes, e.g. by checking if the user has the needed permissions.
See also authorize for the synchronous version of this directive.
See also Authentication vs. Authorization to understand the differences between those.
Example
- Scala
-
source
case class User(name: String) // authenticate the user: def myUserPassAuthenticator(credentials: Credentials): Option[User] = credentials match { case Credentials.Provided(id) => Some(User(id)) case _ => None } // check if user is authorized to perform admin actions, // this could potentially be a long operation so it would return a Future val admins = Set("Peter") def hasAdminPermissions(user: User): Future[Boolean] = Future.successful(admins.contains(user.name)) val route = Route.seal { authenticateBasic(realm = "secure site", myUserPassAuthenticator) { user => path("peters-lair") { authorizeAsync(_ => hasAdminPermissions(user)) { complete(s"'${user.name}' visited Peter's lair") } } } } // tests: val johnsCred = BasicHttpCredentials("John", "p4ssw0rd") Get("/peters-lair") ~> addCredentials(johnsCred) ~> // adds Authorization header route ~> check { status shouldEqual StatusCodes.Forbidden responseAs[String] shouldEqual "The supplied authentication is not authorized to access this resource" } val petersCred = BasicHttpCredentials("Peter", "pan") Get("/peters-lair") ~> addCredentials(petersCred) ~> // adds Authorization header route ~> check { responseAs[String] shouldEqual "'Peter' visited Peter's lair" }
- Java
-
source
import akka.http.javadsl.server.directives.SecurityDirectives.ProvidedCredentials; import static akka.http.javadsl.server.Directives.authorizeAsync; import static akka.http.javadsl.server.Directives.complete; import static akka.http.javadsl.server.Directives.path; class User { private final String name; public User(String name) { this.name = name; } public String getName() { return name; } } // authenticate the user: final Function<Optional<ProvidedCredentials>, Optional<User>> myUserPassAuthenticator = opt -> { if (opt.isPresent()) { return Optional.of(new User(opt.get().identifier())); } else { return Optional.empty(); } }; // check if user is authorized to perform admin actions, // this could potentially be a long operation so it would return a Future final Set<String> admins = new HashSet<>(); admins.add("Peter"); final Set<String> synchronizedAdmins = Collections.synchronizedSet(admins); final Function<User, CompletionStage<Object>> hasAdminPermissions = user -> CompletableFuture.completedFuture(synchronizedAdmins.contains(user.getName())); final Route route = authenticateBasic("secure site", myUserPassAuthenticator, user -> path("peters-lair", () -> authorizeAsync(() -> hasAdminPermissions.apply(user), () -> complete("'" + user.getName() +"' visited Peter's lair") ) ) ).seal(); // tests: final HttpCredentials johnsCred = BasicHttpCredentials.createBasicHttpCredentials("John", "p4ssw0rd"); testRoute(route).run(HttpRequest.GET("/peters-lair").addCredentials(johnsCred)) .assertStatusCode(StatusCodes.FORBIDDEN) .assertEntity("The supplied authentication is not authorized to access this resource"); final HttpCredentials petersCred = BasicHttpCredentials.createBasicHttpCredentials("Peter", "pan"); testRoute(route).run(HttpRequest.GET("/peters-lair").addCredentials(petersCred)) .assertEntity("'Peter' visited Peter's lair");