利用play.api.mvc.Security的机制,实现一个trait,用于扩展controller的用户认证机制。
该trait需要实现的方法包括:
1. def username(request: RequestHeader) = request.session.get("email")
2. def onUnauthorized(request: RequestHeader) = Results.Redirect(routes.Application.login)
3. def isAuthenticated(f: => String => Request[AnyContent] => Result) = {
Authenticated(username, onUnauthorized) { user =>
Action(request => f(user)(request))
}
}
其中:
1. username定义了一个Function1的对象,用于实现从Session中取得登录成功用户的名称,或者是用户ID,根据实际情况进行修改;主要用于Security.Authenticated方法调用是的第一个参数:
* @tparam A the type of the user info value (e.g. `String` if user info consists only in a user name)
* @param userinfo function used to retrieve the user info from the request header
* @param onUnauthorized function used to generate alternative result if the user is not authenticated
* @param action the action to wrap
def Authenticated[A](
userinfo: RequestHeader => Option[A],
onUnauthorized: RequestHeader => Result)(action: A => EssentialAction): EssentialAction
如果该函数返回的Option对象未定义,将会触发onUnauthorized方法;
2. 主要负责在未找到用户登录认证的情况下,将页面跳转到登录页面;
3. Controller中Action的包装器,注意传入参数的类型定义,是一个层层传递的参数的过程函数,首先是String类型的用户登录凭证(存储于Session当中);其次,是Action常规使用的RequestHeader,最后是返回的Action的Result类型;
通过以上的思路,实现一个trait(特质)的时候,可以将其mixin到Controller中,并用isAuthenticated来包装原有的Action.
trait实现样例:
可以将其放在Application控制器相同的文件当中。
控制器的写法变为:
object Application extends Controller with Secured
原有每个Action的实现,将使用withAuth进行替换:
def listUser = withAuth { userid => implicit request => 业务代码 }
通过这样的方式在当前的业务代码中,可以直接使用当前登录用户的凭证,userid。
另外,在trait实现的过程中,增加了一个扩展,withUser。它使用withAuth进行包装,在其中实现通过用户登录凭证,从后台获取的完整的用户信息。那么Action的包装就变为:
def listUser = withUser { user => implicit request => 业务代码 }
这样就可以在业务代码中直接通过user访问到完整的登录用户信息。