Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Akka based authentication and authorisation for Play Framework
package wrappers
import play.api._
import play.api.mvc._
import scala.concurrent._
import scala.concurrent.Future
import play.mvc.Http.Status
import ExecutionContext.Implicits.global
import play.libs.Akka
import akka.actor.{Actor, Props}
import akka.pattern.ask
import akka.util.Timeout
import scala.concurrent.duration._
import play.api.libs.json.{JsObject, Json}
// Authenticated action builder
object Authenticated extends ActionBuilder[AuthenticatedRequest] {
val authenticationActor = Akka.system.actorOf(Props[Authenticator], name = "authentication")
implicit val timeout = Timeout(1 second)
def invokeBlock[A](request: Request[A], block: (AuthenticatedRequest[A]) => Future[SimpleResult]) = {
(authenticationActor ask Authenticate(request)).mapTo[AuthenticationResult] flatMap { result =>
if(result.valid)
block(AuthenticatedRequest[A](result.user, request))
else
block(AuthenticatedRequest[A](None, request))
} recover {
case e => Results.Status(Status.INTERNAL_SERVER_ERROR)
}
}
}
// Authorised helpers
object Authorised {
def async[T](request: Request[T], user: Option[JsObject]) = (block: Future[SimpleResult]) => new Authorised[T](request, user, block)
def apply[T](request: Request[T], user: Option[JsObject]) = (block: SimpleResult) => new Authorised[T](request, user, future{block})
val authorisationActor = Akka.system.actorOf(Props[Authorisor], name = "authorisation")
}
class Authorised[T](request: Request[T], user: Option[JsObject], success: Future[SimpleResult]) {
implicit val timeout = Timeout(1 second)
def authorised = {
(Authorised.authorisationActor ask Authorise(request)).mapTo[AuthorisationResult] map { result =>
result.valid
} recover {
case e => false
}
}
def otherwise(block: => Future[SimpleResult]) : Future[SimpleResult] = authorised.flatMap { valid => if (valid) success else block }
def otherwise(block: => SimpleResult) : SimpleResult = if(authorised.value.get.get) success.value.get.get else block
}
// AuthenticatedRequest wrapper
trait AuthenticatedRequest[+A] extends Request[A] {
val user: Option[JsObject]
}
object AuthenticatedRequest {
def apply[A](u: Option[JsObject], r: Request[A]) = new AuthenticatedRequest[A] {
def id = r.id
def tags = r.tags
def uri = r.uri
def path = r.path
def method = r.method
def version = r.version
def queryString = r.queryString
def headers = r.headers
lazy val remoteAddress = r.remoteAddress
def username = None
val body = r.body
val user = u
}
}
// Case classes for communication using Akka
case class Authenticate[A](request: Request[A])
case class AuthenticationResult(valid: Boolean = false, user: Option[JsObject] = None)
case class Authorise[A](request: Request[A])
case class AuthorisationResult(valid: Boolean = false)
// Actor responsible for authentication
class Authenticator extends Actor {
def receive = {
case Authenticate(request) => sender ! AuthenticationResult(valid = true, user = Some(Json.obj()))
case _ => sender ! AuthenticationResult
}
}
// Actor responsible for authorisation
class Authorisor extends Actor {
def receive = {
case Authorise(request) => sender ! AuthorisationResult(valid = true)
case _ => sender ! AuthorisationResult
}
}
@surenyonjan

This comment has been minimized.

Copy link

surenyonjan commented Feb 25, 2015

Hi, can you please explain from where is that future came inside Authorised.apply block

@EdgeCaseBerg

This comment has been minimized.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.