Skip to content

Instantly share code, notes, and snippets.

@rhiguchi
Created July 23, 2013 04:06
Show Gist options
  • Save rhiguchi/6059786 to your computer and use it in GitHub Desktop.
Save rhiguchi/6059786 to your computer and use it in GitHub Desktop.
Play Framework で Basic 認証を行うアクションのミックスイン ref: http://qiita.com/flo_jack/items/257fe8b0cf93151f8a3d
package controllers
import play.api._
import play.api.mvc._
/**
* 管理者のアカウントを取り扱うモジュール
*/
trait AdminSecure {
import play.api.mvc.Results._
private[this] val accounts = Map("admin" -> "password")
protected val basicRealm = "(my realm)"
/** ユーザー名とパスワードが一致するかを返します */
protected def checkAccount(userName: String, password: String) =
accounts.get(userName).filter(_ == password).nonEmpty
/**
* 認証を確認して実行するアクション
*/
object AdminAction {
private val AUTHORIZATION = "authorization"
private val WWW_AUTHENTICATE = "WWW-Authenticate"
private def realm = "Basic realm=\"%s\"".format(basicRealm)
def apply(f: AuthenticatedRequest[AnyContent] => Result): Action[AnyContent] =
apply(BodyParsers.parse.anyContent)(f)
def apply[A](p: BodyParser[A])(f: AuthenticatedRequest[A] => Result) = Action(p) { request =>
request.headers.get(AUTHORIZATION) match {
case Some(BasicAuthorization(name, pw)) if checkAccount(name, pw) =>
f(new AuthenticatedRequest(name, request))
case _ => Unauthorized("need admin login").withHeaders(WWW_AUTHENTICATE -> realm)
}
}
/**
* Basic 認証の値の取り扱い
*/
private object BasicAuthorization {
private val basicPefix = "Basic "
private val AUTHORIZATION_PARAMS = """([^:]+?):(.+)""".r
/**
* Base64 エンコードで文字列化された Basic 認証値を、ユーザー名とパスワードに分解して返します
*
* @param auth Base64 エンコード文字列
* @return 名前とパスワード
*/
private[this] def decode(auth: String): Option[(String, String)] = {
val d = javax.xml.bind.DatatypeConverter.parseBase64Binary(auth)
new String(d, "utf-8") match {
case AUTHORIZATION_PARAMS(username, password) => Some(username, password)
case _ => None
}
}
/**
* WWW-Authenticate ヘッダの値から、ユーザー名とパスワードを取り出します。
*
* @param authorization WWW-Authenticate ヘッダ値。ヘッダの名前は含まない。
* @return 名前とパスワード
*/
def unapply(authorization: String): Option[(String, String)] = authorization match {
case s if s startsWith basicPefix => decode(s drop basicPefix.length)
case _ => None
}
}
/** 認証されて実行するリクエスト */
class AuthenticatedRequest[A] private[controllers]
(val userName: String, request: Request[A]) extends WrappedRequest(request)
}
}
package controllers
import play.api._
import play.api.mvc._
object Application extends Controller with AdminSecure {
def adminHome = AdminAction { implicit request =>
Ok("Welcome back, " + request.userName)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment