Play 2.5 disable csrf protection for some requests

℡╲_俬逩灬. 提交于 2019-12-01 07:17:15

问题


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.

The route paths will need to be in the compiled form, so a route like ´/foo/bar´ would be /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!



来源:https://stackoverflow.com/questions/37408269/play-2-5-disable-csrf-protection-for-some-requests

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