一:Play框架中应用@With注解主要作用是在某个action执行之前先执行@with注解申明的action,一般用来做权限安全控制。play权限安全控制主要有3个方法。
- @Security.Authenticated on each Action -------------------->在action之前用@Security.Authenticated注解
- @With using a custom Action --------------------------------->在action调用之前用@With注解调用自定义的action
- @With on a controller using a custom Action--------------->在控制器类前用@With注解
(1).@Security.Authenticated
我将使用最基本的token-based验证来演示,模型层的模型如下。
<span style="font-size:18px;">public User extends Model {
@Id
public Integer id;
public String username;
public String authToken;
public static Finder<Integer,User> find = new Finder(Integer.class, User.class);
}</span>
@Security.Authenticated注解会被所有使用该注解的action执行校验,它默认会调用类
Security.Authenticator
中的方法getUsername(Http.Context ctx),尝试取出session cookies中存储的username,如果username存在,那么被注解修饰的action会正常的执行,如果username不存在,那么会返回401错误码。
幸运的是,我们可以实现我们自己的认证器Authenticator去检查authentication token。代码如下:
public class ActionAuthenticator extends Security.Authenticator {
@Override
public String getUsername(Http.Context ctx) {
String token = getTokenFromHeader(ctx);
if (token != null) {
User user = User.find.where().eq("authToken", token).findUnique();
if (user != null) {
return user.username;
}
}
return null;
}
@Override
public Result onUnauthorized(Http.Context context) {
return super.onUnauthorized(context);
}
private String getTokenFromHeader(Http.Context ctx) {
String[] authTokenHeaderValues = ctx.request().headers().get("X-AUTH-TOKEN");
if ((authTokenHeaderValues != null) && (authTokenHeaderValues.length == 1) && (authTokenHeaderValues[0] != null)) {
return authTokenHeaderValues[0];
}
return null;
}
}
控制器中使用该自定义的
Authenticator
<span style="font-size:18px;">@Security.Authenticated(ActionAuthenticator.class)
public static Result awesomeAction() {
return ok("Very awesome content!");
}</span>
(2)@With using a custom Action
@With注解在目标action执行之前执行,我们可以使用该注解来对我们的权限安全进行验证。代码如下:
<span style="font-size:18px;">public class SecuredAction extends Action.Simple {
public F.Promise<Result> call(Http.Context ctx) throws Throwable {
String token = getTokenFromHeader(ctx);
if (token != null) {
User user = User.find.where().eq("authToken", token).findUnique();
if (user != null) {
ctx.request().setUsername(user.username);
return delegate.call(ctx);
}
}
Result unauthorized = Results.unauthorized("unauthorized");
return F.Promise.pure(unauthorized);
}
private String getTokenFromHeader(Http.Context ctx) {
String[] authTokenHeaderValues = ctx.request().headers().get("X-AUTH-TOKEN");
if ((authTokenHeaderValues != null) && (authTokenHeaderValues.length == 1) && (authTokenHeaderValues[0] != null)) {
return authTokenHeaderValues[0];
}
return null;
}
}</span>
现在我们在我们的目标action上使用该注解
<span style="font-size:18px;">@With(SecuredAction.class)
public static Result anotherAwesomeAction() {
return ok("The best content!");
}</span>
(3)@With on a controller using a custom Action
有时候我们每个目标都需要在目标action执行之前检查权限安全,若此时给每个目标action都标记上@With注解,这显然是很繁琐的,幸运的是我们可以通过在控制器类上使用该注解来达到控制器中每个目标action执行之前都先执行注解标记的action,这样就大大提高了开发效率,并且易于维护。代码如下:
<span style="font-size:18px;">@With(SecuredAction.class)
public class SomeController extends Controller {
...
}</span>
还有一种情况就是我不想在controller控制器上使用注解该怎么办,抑或我有多个控制器都需要使用该注解,办法很简单,如下:
<span style="font-size:18px;">@With(SecuredAction.class)
public abstract class SecuredController extends Controller {}</span>
<span style="font-size:18px;">public class SomeOtherController extends SecuredController {
...
}</span>