405 Method Not Allowed on /api/login OPTIONS reque

2019-05-28 13:18发布

In my app, I am using grails-spring-security-rest plugin and I am currently at the stage of building authentication flow.

If I use a rest client everything works as expected: I am able to login by posting username & password in json and get tokens back. Perfect!

Now, I am trying to integrate this whole thing with the web form and, of course, the browser sends preflight OPTIONS request.

I have a simple interceptor setup:

@GrailsCompileStatic
class CorsInterceptor {
    int order = HIGHEST_PRECEDENCE

    CorsInterceptor() {
        matchAll() // match all controllers
        //.excludes(controller:"login")   // uncomment to add exclusion
    }

    boolean before() {
        String origin = request.getHeader("Origin");

        boolean options = "OPTIONS".equals(request.getMethod());
        if (options) {
            if (origin == null) return;
            response.addHeader("Access-Control-Allow-Headers", "origin, authorization, accept, content-type, x-requested-with");
            response.addHeader("Access-Control-Allow-Methods", "GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS");
            response.addHeader("Access-Control-Max-Age", "3600");
        }

        response.addHeader("Access-Control-Allow-Origin", origin == null ? "*" : origin);
        response.addHeader("Access-Control-Allow-Credentials", "true");

        true // proceed to controller
    }

    boolean after() { true }

    void afterView() {
        // no-op
    }

}

The interceptor works perfectly got valid get requests and adds the headers into the response. However, when I am trying to senf this:

curl -X "OPTIONS" "http://localhost:8080/api/login" \
    -H "Origin: http://localhost:3000" \
    -H "Content-Type: application/json" \
    -d "{\"username\":\"customer\",\"password\":\"password\"}"

I am always getting 405 Method Not Allowed back and the execution is not even getting to interceptor at all.

My assumption is that the login controller provided by the plugin is not allowing that, and I need to put an additional URL mapping to overcome this problem. My problem is, what this mapping support to look like?

Also, it is possible to setup mapping that will work for all OPTIONS requests, so I don' need to specify them one by one?

Given all that, it is only my assumption... Am I even in the right direction with it?

Thanks,

2条回答
Lonely孤独者°
2楼-- · 2019-05-28 13:41

this problem was faced by many other users as well and was repeatedly asked on github and slack channels. I've created a sample example which has CORS filter in under src/ directory and I've registered it as spring bean. Here is github repo with example app. The Cors filter code is below

@Priority(Integer.MIN_VALUE)
class CorsFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest req, HttpServletResponse resp, FilterChain chain)
        throws ServletException, IOException {

    String origin = req.getHeader("Origin");

    boolean options = "OPTIONS".equals(req.getMethod());
    if (options) {
        if (origin == null) return;
        resp.addHeader("Access-Control-Allow-Headers", "origin, authorization, accept, content-type, x-requested-with");
        resp.addHeader("Access-Control-Allow-Methods", "GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS");
        resp.addHeader("Access-Control-Max-Age", "3600");
    }

    resp.addHeader("Access-Control-Allow-Origin", origin == null ? "*" : origin);
    resp.addHeader("Access-Control-Allow-Credentials", "true");

    if (!options) chain.doFilter(req, resp);
}
}

Register this as spring bean in resources.groovy file as below:

beans = {
    corsFilter(CorsFilter)
}

Here is the question asked on github repo of this plugin.

Update Grails3 CORS interceptor plugin has been update to include SpringSecurityCorsFilter. For details of how to use, refer to this sample

This plugin is much better than the servlet filter I've written above.

查看更多
冷血范
3楼-- · 2019-05-28 13:57

Shurik, the 'filters' you speak of are now called 'interceptors' to match more common nomenclature. This 'filter' is NOT deprecated as this is an 'ACTUAL' filter in Grails/SpringBoot. This is why they deprecated the Interceptors from being called this because of all the naming confusion.

查看更多
登录 后发表回答