使用grails-spring-security-rest插件的/ api / login OPTIONS请求不允许405方法(并继续战斗...)

时间:2016-04-04 09:51:01

标签: spring rest grails cors

在我的应用程序中,我使用的是grails-spring-security-rest插件,目前我正处于构建身份验证流程的阶段。

如果我使用休息客户端,一切都按预期工作:我可以通过发布用户名&在json中输入密码并获取令牌。完美!

现在,我正在尝试将整个内容与网络表单集成,当然,浏览器会发送预检OPTIONS请求。

我有一个简单的拦截器设置:

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

}

拦截器完美地获得了有效的get请求,并将标头添加到响应中。但是,当我试图这样做时:

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

我总是得到405 Method Not Allowed,执行甚至根本没有进入拦截器。

我的假设是插件提供的登录控制器不允许这样做,我需要添加一个额外的URL映射来克服这个问题。我的问题是,这个映射支持看起来像什么?

此外,可以设置适用于所有OPTIONS请求的映射,因此我不需要逐个指定它们吗?

鉴于这一切,这只是我的假设......我是否正朝着正确的方向前进?

谢谢,

2 个答案:

答案 0 :(得分:5)

许多其他用户也遇到了这个问题,并且在github和slack频道上反复询问。我已经创建了一个示例示例,它在src /目录下有CORS过滤器,我已将其注册为spring bean。 Here is github repo与示例应用程序。 Cors过滤器代码位于

之下
@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);
}
}

在resources.groovy文件中将其注册为spring bean,如下所示:

beans = {
    corsFilter(CorsFilter)
}

Here is在github repo上询问此插件的问题。

<强>更新 Grails3 CORS interceptor plugin已更新,包括SpringSecurityCorsFilter。有关如何使用的详细信息,请参阅this sample

这个插件比我上面写的servlet过滤器要好得多。

答案 1 :(得分:0)

Shurik,您所说的“过滤器”现在称为“拦截器”,以匹配更常见的术语。不建议使用此“过滤器”,因为在Grails / SpringBoot中这是“实际”过滤器。这就是为什么由于所有命名混乱而使Interceptor不被称为Interceptor的原因。