您可以装饰CSRFFilter 并使用路由路径列表来包含或排除过滤器的应用。
路由路径需要采用编译后的形式,因此像 '/foo/bar' 这样的路由将是 /profile,但带有动态组件的路由像 /view/:foo/:bar 会变成 /view/$foo<[^/]+>/$bar<[^/]+>。在开发模式下,您可以通过转到未映射的 URL(例如http://localhost:9000/@foo)来列出路由的编译版本。
import java.util.LinkedList;
import java.util.List;
import javax.inject.Inject;
import akka.util.ByteString;
import play.filters.csrf.CSRFFilter;
import play.libs.streams.Accumulator;
import play.mvc.EssentialAction;
import play.mvc.EssentialFilter;
import play.mvc.Result;
import play.routing.Router;
public class MaybeCsrfFilter extends EssentialFilter {
private final EssentialFilter csrfFilter;
private final List<String> applyCsrf = new LinkedList<>();
@Inject
public MaybeCsrfFilter(final CSRFFilter csrfFilter) {
this.csrfFilter = csrfFilter.asJava();
// alternatively, define the inclusion/exclusion list in the config and inject Configuration to obtain it
applyCsrf.add("/foo/bar");
applyCsrf.add("/view/$foo<[^/]+>/$bar<[^/]+>");
}
@Override
public EssentialAction apply(final EssentialAction next) {
return EssentialAction.of(request -> {
final Accumulator<ByteString, Result> accumulator;
final String currentRoute = request.tags().get(Router.Tags.ROUTE_PATTERN);
if (applyCsrf.contains(currentRoute)) {
accumulator = csrfFilter.apply(next).apply(request);
} else {
accumulator = next.apply(request);
}
return accumulator;
});
}
}
这是蛮力的,您必须使您的过滤器与包含/排除列表保持同步,但它确实有效。
或者,您可以使用 routes 文件中的 cmets 来确定哪些路由不应应用 CSRF 过滤器。
对于routes 之类的文件
#NOCSRF
GET /foo/bar controllers.Application.foo()
#NOCSRF
GET /view/:hurdy/:gurdy controllers.Application.bar()
GET /something/else controllers.Application.bar()
此过滤器实现不会将 CSRF 过滤器应用于其路由以# NOCSRF 开头的任何操作。对于此示例,只有 /something/else 将应用 CSRF 过滤器。
public EssentialAction apply(final EssentialAction next) {
return EssentialAction.of(request -> {
final Accumulator<ByteString, Result> accumulator;
final String routeComment = request.tags().get(Router.Tags.ROUTE_COMMENTS);
if ("NOCSRF".equals(routeComment)) {
accumulator = next.apply(request);
} else {
accumulator = csrfFilter.apply(next).apply(request);
}
return accumulator;
});
}
你的Filters 定义就变成了
public class Filters implements HttpFilters {
private final MaybeCsrfFilter csrf;
@Inject
public Filters(final MaybeCsrfFilter csrf) {
this.csrf = csrf;
}
@Override
public EssentialFilter[] filters() {
return new EssentialFilter[]{csrf};
}
}
别忘了为MaybeCsrfFilter创建一个绑定!