Skip to content

Instantly share code, notes, and snippets.

@markusjura
Last active June 22, 2019 19:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save markusjura/9596535 to your computer and use it in GitHub Desktop.
Save markusjura/9596535 to your computer and use it in GitHub Desktop.
package controllers
import play.api.mvc._
import play.api.data.Form
import play.api.data.Forms._
import models._
import play.api.mvc.Security._
import scala.concurrent.Future
import play.api.Play._
import models.LoginData
import play.api.libs.concurrent.Execution.Implicits._
object Application extends SecuredController {
val usernameSessionKey = "username"
val tokenSessionKey = "token"
val bidServiceUrlSessionKey = "bidServiceUrl"
/**
* Retrieve username from session
*/
def requestUsername(request: RequestHeader) = request.session.get(usernameSessionKey)
/**
* Redirect to login page
*/
def onUnauthorized(request: RequestHeader) = Redirect(routes.Application.login)
def index = Authenticated(requestUsername, onUnauthorized) { username =>
Action { implicit request =>
Ok(views.html.index())
}
}
def login = Action { implicit request =>
Ok(views.html.login(loginForm))
}
val loginForm: Form[LoginData] = Form {
mapping(
"username" -> nonEmptyText(minLength = 4), //verify the username
"password" -> nonEmptyText(minLength = 4) //verify the password
)(LoginData.apply)(LoginData.unapply)
}
def loginSubmit = Action.async { implicit request =>
//methods for handling a form. Notice that the return type has to be the same
def onError(formWithErrors: Form[LoginData]) =
Future.successful(BadRequest(views.html.login(formWithErrors)))
def onSuccess(loginData: LoginData) = {
// login data passed requirements. Check if the user and password exist on the server side.
authenticate(loginData) map {
// Authentication failed
case AuthError(authErrorMessage) => {
val errorForm = loginForm.fill(loginData).withGlobalError(authErrorMessage)
BadRequest(views.html.login(errorForm))
}
// Authentication successful
case AuthOK(token) => {
Redirect(routes.Application.index).withSession(
usernameSessionKey -> loginData.username,
tokenSessionKey -> token)
}
}
}
loginForm.bindFromRequest.fold(onError, onSuccess)
}
def loginSubmitBlocking = Action { implicit request =>
//methods for handling a form. Notice that the return type has to be the same
def onError(formWithErrors: Form[LoginData]) =
BadRequest(views.html.login(formWithErrors))
def onSuccess(loginData: LoginData) = {
// login data passed requirements. Check if the user and password exist on the server side.
val response = authenticateBlocking(loginData)
response match {
// Authentication failed
case AuthError(authErrorMessage) => {
val errorForm = loginForm.fill(loginData).withGlobalError(authErrorMessage)
BadRequest(views.html.login(errorForm))
}
// Authentication successful
case AuthOK(token) => {
Redirect(routes.Application.index).withSession(
usernameSessionKey -> loginData.username,
tokenSessionKey -> token)
}
}
}
loginForm.bindFromRequest.fold(onError, onSuccess)
}
/**
* Logout user with new session
*/
def logout = Action { implicit request =>
Redirect(routes.Application.login).withNewSession
}
}
username=user-1&password=pass
POST /login controllers.Application.loginSubmit()
POST /loginBlocking controllers.Application.loginSubmitBlocking()
package controllers
import scala.concurrent._
import scala.concurrent.duration._
import play.api.Play._
import play.api.libs.ws.WS
import play.api.libs.json.Json
import play.api.mvc.Controller
import models.LoginData
import play.api.libs.concurrent.Execution.Implicits._
import play.api.Logger
import org.joda.time.DateTime
/**
* Secured Controller
*/
trait SecuredController extends Controller {
sealed trait AuthResult
case class AuthError(authErrorMessage: String) extends AuthResult
case class AuthOK(token: String) extends AuthResult
/**
* Authenticate user with password against the auth service
* @param loginData contains username and password
* @return AuthOK with token if user has been authenticated successfully
* AuthError with error message if authentication failed
*/
def authenticate(loginData: LoginData): Future[AuthResult] = {
val authServiceUrl = configuration.getString("service.auth.url").get
WS.url(s"$authServiceUrl/auth")
.post(Json.toJson(loginData))
.map { response =>
response.status match {
case OK => AuthOK((response.json \ "token").as[String])
case _ => AuthError((response.json \ "error").as[String])
}
}
}
/**
* Authenticate user with password against the auth service
* @param loginData contains username and password
* @return AuthOK with token if user has been authenticated successfully
* AuthError with error message if authentication failed
*/
def authenticateBlocking(loginData: LoginData): AuthResult = {
val authServiceUrl = configuration.getString("service.auth.url").get
val future = WS.url(s"$authServiceUrl/auth")
.post(Json.toJson(loginData))
val response = Await.result(future, 1.seconds)
response.status match {
case OK => AuthOK((response.json \ "token").as[String])
case _ => AuthError((response.json \ "error").as[String])
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment