Play 2.5 disable csrf protection for some requests

匿名 (未验证) 提交于 2019-12-03 02:29:01

问题:

I'm writing my app using play framework v. 2.5.3 and use CSRF protection as it is described in official documentation.

public class Filters implements HttpFilters {  @Inject CSRFFilter csrfFilter;  @Override public EssentialFilter[] filters() {     return new EssentialFilter[]{csrfFilter.asJava()}; }}

Of course, it works, as long as all of requests need to be filtered, but some of them should be bypassed. How can filters be configured to bypass requests to some specified route? Thanks for your help!

回答1:

You can decorate CSRFFilter and use a list of route paths to either include or exclude the application of the filter.

/profile but a route with dynamic components like /view/:foo/:bar becomes /view/$foo<[^/]+>/$bar<[^/]+>. You can list the compiled versions of the routes by going to an unmapped URL (e.g. http://localhost:9000/@foo) when in development mode.

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;         });     } }

It's brute force, and you have to keep your filters in sync with the inclusion/exclusion list, but it works.

Alternatively, you can use comments in the routes file to determine which routes should not have the CSRF filter applied.

For a routes file like

#NOCSRF GET   /foo/bar               controllers.Application.foo() #NOCSRF GET   /view/:hurdy/:gurdy    controllers.Application.bar() GET   /something/else        controllers.Application.bar()

This filter implementation will not apply the CSRF filter to any action whose route is preceded by # NOCSRF. For this example, only /something/else will have the CSRF filter applied to it.

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;     }); }

Your Filters definition then becomes

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};     } }

Don't forget to create a binding for MaybeCsrfFilter!



标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!