Mar*_*tin 9 authentication scala composition playframework playframework-2.0
我正在使用Play的ActionBuilder创建各种保护我的控制器的操作.例如,我实现IsAuthenticated了以确保只有在用户登录时才能访问某些操作:
case class AuthRequest[A](user: String, request: Request[A]) extends WrappedRequest[A](request)
private[controllers] object IsAuthenticated extends ActionBuilder[AuthRequest] {
def invokeBlock[A](req: Request[A], block: (AuthRequest[A]) => Future[SimpleResult]) = {
req.session.get("user").map { user =>
block(new AuthRequest(user, req))
} getOrElse {
Future.successful(Results.Unauthorized("401 No user\n"))
}
}
}
Run Code Online (Sandbox Code Playgroud)
使用IsAuthenticated我可以(1)将操作限制为已登录的用户,以及(b)访问登录的用户:
def auth = IsAuthenticated { implicit authRequest =>
val user = authRequest.user
Ok(user)
}
Run Code Online (Sandbox Code Playgroud)
此外,我使用ActionBuilder HasToken来确保在请求的标头中存在令牌时调用了一个动作(并且,我可以访问令牌值):
case class TokenRequest[A](token: String, request: Request[A]) extends WrappedRequest[A](request)
private[controllers] object HasToken extends ActionBuilder[TokenRequest] {
def invokeBlock[A](request: Request[A], block: (TokenRequest[A]) => Future[SimpleResult]) = {
request.headers.get("X-TOKEN") map { token =>
block(TokenRequest(token, request))
} getOrElse {
Future.successful(Results.Unauthorized("401 No Security Token\n"))
}
}
}
Run Code Online (Sandbox Code Playgroud)
这样,我可以确保使用该令牌调用操作:
def token = HasToken { implicit tokeRequest =>
val token = tokeRequest.token
Ok(token)
}
Run Code Online (Sandbox Code Playgroud)
到现在为止还挺好...
但是,我怎么能包装(或嵌套/组合)上面定义的那些动作呢?例如,我想确保(a)用户将登录并且(b)该令牌将存在:
def tokenAndAuth = HasToken { implicit tokeRequest =>
IsAuthenticated { implicit authRequest =>
val token = tokeRequest.token
val user = authRequest.user
}
}
Run Code Online (Sandbox Code Playgroud)
但是,上述操作无法编译.我尝试了许多不同的实现,但总是无法实现所需的行为.
一般而言:我怎样才能以任意顺序Action使用Play定义ActionBuilder?在上面的例子中,它不会有问题,如果我想包IsAuthenticated中HasToken或周围其他方式-的影响将是相同的:用户必须先登录,并必须出示令牌.
ActionBuilders不是用于临时组合,而是用于构建操作层次结构,因此您最终只能在整个控制器中使用几个操作.
所以在你的例子中,你应该建立IsAuthenticated在HasToken我在这里说明的顶部.
这是一个可行的解决方案,实际上可以简化您的代码.你真的需要经常在现场作曲吗?
使用EssentialActions可以实现特别的组合(仅仅因为他们没有从2.1改变),但他们有一些缺点,正如Johan指出的那样.它们的API也不是真正用于临时使用,并且Iteratees对于控制器操作来说太低级且太麻烦.
所以最后你的最后一个选择就是直接编写Actions.默认情况下,操作不支持传递WrappedRequest(这就是ActionBuilder存在的原因).但是,您仍然可以传递WrappedRequest并与其进行下一个Action处理.
以下是迄今为止我提出的最好的,我猜是相当脆弱的.
case class HasToken[A](action: Action[A]) extends Action[A] {
def apply(request: Request[A]): Future[SimpleResult] = {
request.headers.get("X-TOKEN") map { token =>
action(TokenRequest(token, request))
} getOrElse {
Future.successful(Results.Unauthorized("401 No Security Token\n"))
}
}
lazy val parser = action.parser
}
case class IsAuthenticated[A](action: Action[A]) extends Action[A] {
def apply(request: Request[A]): Future[SimpleResult] = {
request.session.get("user").map { user =>
action(new AuthRequest(user, request))
} getOrElse {
Future.successful(Results.Unauthorized("401 No user\n"))
}
}
lazy val parser = action.parser
}
object ActionComposition extends Controller {
def myAction = HasToken {
Action.async(parse.empty) { case TokenRequest(token, request) =>
Future {
Ok(token)
}
}
}
def myOtherAction = IsAuthenticated {
Action(parse.json) { case AuthRequest(user, request) =>
Ok
}
}
def both = HasToken {
IsAuthenticated {
Action(parse.empty) { case AuthRequest(user, request: TokenRequest[_]) =>
Ok(request.token)
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
您还可以在结果级别进行撰写,仅使用内置操作.这在尝试分解错误处理和其他重复的东西时尤其有用.我在这里有一个例子.
我们仍然缺少Play 2.1的动作组合提供的功能.到目前为止,似乎ActionBuilder + Result组合作为其继任者的赢家.
| 归档时间: |
|
| 查看次数: |
4993 次 |
| 最近记录: |