I wanted to post up a quick example app after spending a lot of time working through issues and questions on my own.
First thing first. We are going to use the quick start for a new project. The quickest method is to use n8han/giter8 ( https://github.com/n8han/giter8 ). We will also use MongoDB with Lift’s Mongo-Record for a quick user model.
One installed we are going to create our basic project.
$ g8 scalatra/scalatra-sbt
> organization [com.example]:
> name [scalatra-sbt-prototype]: scalatra-auth
> servlet_name [MyScalatraFilter]:
> scala_version [2.9.0-1]:
> version [1.0]:
$ cd scalatra-auth
If you do not have SBT installed at this point follow setup docs (https://github.com/harrah/xsbt/wiki/Setup).
In `Build.sbt` add the library dependencies below.
"net.liftweb" %% "lift-json" % "2.4-M3",
"net.liftweb" %% "lift-mongodb-record" % "2.4-M3"
Create a new file `/src/main/scala/AuthenticationSupport.scala` this file is used to tell the Scalate servlet how to support authenticating our used model we are about to create.
import org.scalatra.auth.{ScentryConfig, ScentrySupport}
import org.scalatra.ScalatraKernel
import org.scalatra.auth.strategy.{BasicAuthStrategy, BasicAuthSupport}
import org.scalatra.auth.{ScentrySupport, ScentryConfig}
trait AuthenticationSupport extends ScentrySupport[User] with BasicAuthSupport[User] { self: ScalatraKernel =>
val realm = "test"
protected def contextPath = request.getContextPath
protected def fromSession = { case id: String => User.find("_id",id)
openOr null }
protected def toSession = { case usr: User => usr.id.toString() }
protected val scentryConfig = (new
ScentryConfig{}).asInstanceOf[ScentryConfiguration]
override protected def configureScentry = {
scentry.unauthenticated {
scentry.strategies('Basic).unauthenticated()
}
}
override protected def registerAuthStrategies = {
scentry.registerStrategy('Basic, app =>
new OurBasicAuthStrategy(app, realm))
}
}
The registered strategy in the example above needs created now place that in `src/main/scala/OurBasicAuthStrategy.scala`.
import javax.servlet.http.{HttpServletResponse, HttpServletRequest}
import net.iharder.Base64
import org.scalatra.{ScalatraKernel}
import net.liftweb.mongodb._
import net.liftweb.mongodb.record._
import org.scalatra.auth.strategy.{BasicAuthStrategy, BasicAuthSupport}
import org.scalatra.auth.{ScentrySupport, ScentryConfig}
class OurBasicAuthStrategy(protected override val app: ScalatraKernel,
realm: String)
extends BasicAuthStrategy[User](app, realm) {
protected def validate(userName: String, password: String): Option[User] = {
return User.login(userName, password)
}
protected def getUserId(user: User): String = user.userIdAsString
}
Now we will need all of our user functions to register, login, and validate the session. Create the user model in `src/main/scala/User.scala`.
import java.util.regex.Pattern
import net.liftweb.mongodb.record._
import net.liftweb.mongodb.record.field._
import net.liftweb.record.field._
import net.liftweb.record._
import org.bson.types._
import org.joda.time.{DateTime, DateTimeZone}
import net.liftweb.mongodb.record.MongoRecord
import net.liftweb.json.DefaultFormats
import net.liftweb.json.JsonDSL._
import net.liftweb.json.JsonAST.JObject
class User extends MongoRecord[User] with MongoId[User] {
def meta = User
object username extends StringField(this, 200)
object password extends StringField(this, 200)
def userIdAsString: String = id.toString
def login(u: String, p: String): Option[User] = {
val user = User.findAll(("username" -> u), ("password" -> p))
Some(user.first)
}
}
object User extends User with MongoMetaRecord[User] {
}
Now that we have our Authentication support and our User model we need to create the actual handing within our example application.
import org.scalatra._
import java.net.URL
import scalate.ScalateSupport
import net.liftweb.mongodb._
import net.liftweb.json._
import net.liftweb.mongodb.record.MongoRecord
class MyScalatraFilter extends ScalatraFilter with ScalateSupport with AuthenticationSupport{
beforeAll {
MongoDB.defineDb(DefaultMongoIdentifier, MongoAddress(MongoHost("127.0.0.1", 27017), "scalatra-auth"))
}
get("/") {
Hello, world!
Say hello to Scalate.
Test Auth Register.
}
get("/login") {
contentType = "text/html"
Login
}
post("/login") {
basicAuth
redirect("/loggedin")
}
get("/loggedin") {
contentType = "text/html"
basicAuth
Hello, world!
Welcome {user.username} you are logged in.
}
get("/register") {
contentType = "text/html"
Register
}
afterAll {
MongoDB.close
}
post("/register") {
val u = User.createRecord
.username(params("userName"))
.password(params("password"))
u.save
redirect("/login")
}
notFound {
// If no route matches, then try to render a Scaml template
val templateBase = requestPath match {
case s if s.endsWith("/") => s + "index"
case s => s
}
val templatePath = "/WEB-INF/scalate/templates/" + templateBase + ".scaml"
servletContext.getResource(templatePath) match {
case url: URL =>
contentType = "text/html"
templateEngine.layout(templatePath)
case _ =>
filterChain.doFilter(request, response)
}
}
}
Now we should verify all the hard work we put into this test application pays off. (Make sure you have Mongod running)
$ sbt jetty-run
You will be able to walk through a basic registration and authentication process now.
To clone or review this code please visit github (https://github.com/jlarmstrong/scalatra-auth-example).