Authorisation check in controller - Scala/Play

2019-03-27 14:51发布

This is a simple example of a controller in Play Framework where every action checks the session - if the user is logged in.

object Application extends Controller {

    def index = Action { implicit request =>
        if (request.session.isEmpty) {
            Redirect("/login")
        } else {
            Ok(views.html.index("index"))
        }
    }

    def about = Action { implicit request =>
        if (request.session.isEmpty) {
            Redirect("/login")
        } else {
            Ok(views.html.index("about"))
        }
    }

}

I'd like to handle the session checking in the constructor instead of every action method, but I just don't know how? It should look something like this:

object Application extends Controller {

    //This is where the constructor would check if session exists
    //and if not - redirect to login screen

    def index = Action {
        Ok(views.html.index("index"))
    }

    def about = Action {
        Ok(views.html.index("about"))
    }

}

Is this possible and if so then how?

My stack is Play Framework 2.2.1, Scala 2.10.3, Java 1.8.0-ea 64bit

UPDATE - SOLVED Thanks for all your ideas, solution is now found, see my answer.

4条回答
劫难
2楼-- · 2019-03-27 15:25

You could use a Filter, which applies to every request in the application. However, then you would need to have some code in that Filter to allow certain URLs to be accessed without a valid session, otherwise then the user would not be able to login in the first place.

查看更多
我只想做你的唯一
3楼-- · 2019-03-27 15:34

Take a look at Deadbolt: https://github.com/schaloner/deadbolt-2 . There are exhaustive examples and guides.

Works perfectly in my Play 2 project.

查看更多
可以哭但决不认输i
4楼-- · 2019-03-27 15:48

You could take advantage of Action Composition to achieve this. From the documentation:

import play.api.mvc._

class AuthenticatedRequest[A](val username: String, request: Request[A]) extend WrappedRequest[A](request)

object Authenticated extends ActionBuilder[AuthenticatedRequest] {
  def invokeBlock[A](request: Request[A], block: (AuthenticatedRequest[A]) =>Future[SimpleResult]) = {
    request.session.get("username").map { username =>
      block(new AuthenticatedRequest(username, request))
    } getOrElse {
      Future.successful(Forbidden)
    }
  }
}

And then you could simply do:

def index = Authenticated {
    Ok(views.html.index("index"))
}

Alternatively you could set up a filter instead (as @Robin Green suggested) like so:

object AuthFilter extends Filter {

  override def apply(next: RequestHeader => Result)(rh: RequestHeader): Result = {
    rh.session.get("username").map { user =>
      next(rh)
  }.getOrElse {
    Redirect("/login")
  }
}

In Global.scala scala, add

override def doFilter(action: EssentialAction) = AuthFilter(action)

For more on Filters, see the official docs

查看更多
Ridiculous、
5楼-- · 2019-03-27 15:50

Solution is to use Action Composition and create a custom action.

Auth.scala:

package core

import play.api.mvc._
import scala.concurrent._
import play.api.mvc.Results._

object AuthAction extends ActionBuilder[Request] {

    def invokeBlock[A](request: Request[A], block: (Request[A]) => Future[SimpleResult]) = {
        if (request.session.isEmpty) {
            //authentication condition not met - redirect to login page
            Future.successful(Redirect("/login"))
        } else {
            //proceed with action as normal
            block(request)
        }
    }

}

Application.scala:

package controllers

import play.api._
import play.api.mvc._
import core._

object Application extends Controller {

    def index = AuthAction {
        Ok(views.html.index("You are logged in."))
    }

}
查看更多
登录 后发表回答