4

更新:我已将此问题更改为关于我遇到的具体问题。这是因为 Grails 2.0 将支持过滤器的单元测试,所以希望文档会更好。

我正在尝试为我设置的过滤器编写单元测试,以在我的 grails 应用程序中实现 Shiro 安全性。我正在使用 Grails 1.3.7,并且在一段时间内(如果有的话)将无法在这个特定项目中使用 2.0。

我的过滤器背后的想法是我需要匿名访问数字或控制器/操作组合,但保护对其他人的访问。我还希望它能够安全失败,即如果您忘记明确允许访问,则禁止访问。

过滤器类

class SecurityFilters {
    def filters = {

        homeAccess(controller: "home", action: "*") {
            before = {

                // Allow all access
                request.accessAllowed = true
            }
        }

        serverAccess(controller: "server", action: "list") {
            before = {

                // Allow all access
                request.accessAllowed = true
            }
        }

        layerAccess(controller: "layer", action: "list|listBaseLayersAsJson|listNonBaseLayerAsJson|showLayerByItsId") {
            before = {

                // Allow all access
                request.accessAllowed = true
            }
        }

        all(uri: "/**") {
            before = {

                // Check if request has been allowed by another filter
                if (request.accessAllowed) return true            

                // Ignore direct views (e.g. the default main index page).
                if (!controllerName) return true

                // Access control by convention.
                accessControl(auth: false)
            }
        }
    }
}

单元测试

import org.codehaus.groovy.grails.plugins.web.filters.FilterConfig

class SecurityFiltersTests extends FiltersUnitTestCase {

    protected void setUp() {
        super.setUp()
    }

    protected void tearDown() {
        super.tearDown()
    }

    void testHomeControllerFilter() {

        checkFilter('homeAccess')
    }

    void testServerControllerFilter() {

        checkFilter('serverAccess')
    }

    void testLayerControllerFilter() {

        checkFilter('layerAccess')
    }

    void testAllFilter() {

        assertTrue "Write tests", false
    }

    void checkFilter(String filterName) {

        FilterConfig filter = initFilter(filterName)
        assertNotNull filterName + " filter should exist", filter
        assertExistsBefore(filterName)

        assertEquals "accessAllowed should be null to start with", null, filter.request.accessAllowed

        // Run filter
        filter.before()

        assertEquals "accessAllowed should be true now", true, filter.request.accessAllowed
    }
}

例外

问题是,当这些测试运行时,我得到以下异常:

No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.

java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
    at grails.test.MockUtils$_addCommonWebProperties_closure32.doCall(MockUtils.groovy:316)
    at shiro.SecurityFilters$_closure1_closure5_closure12.doCall(SecurityFilters.groovy:40)
    at shiro.SecurityFilters$_closure1_closure5_closure12.doCall(SecurityFilters.groovy)
    at shiro.SecurityFiltersTests.checkFilter(SecurityFiltersTests.groovy:92)
    at shiro.SecurityFiltersTests$checkFilter.callCurrent(Unknown Source)
    at shiro.SecurityFiltersTests.testLayerControllerFilter(SecurityFiltersTests.groovy:65)

此外,我在单元测试中放置了以下行:

println "filter.request: " + filter.request

打印以下内容:

filter.request: org.codehaus.groovy.grails.plugins.testing.GrailsMockHttpServletRequest@2914cca4

所以它肯定似乎使用了一个模拟请求对象。

所以,问题。

我是否正确使用 FiltersUnitTestCase 来执行我的过滤器?

如果是这样:

为什么我会遇到此异常?

4

1 回答 1

1

提醒每个人的调试规则:不断删除代码,直到找到问题所在的确切行。即使很明显线路没有引起问题。因为:有时它实际上是

作为调试工作的一部分,我的过滤器中有以下代码行:

println "controllerName = '${controllerName}', actionName = '${actionName}'"

这是直接在该行之前:

request.accessAllowed = true

我已将其从粘贴到此问题中的代码中取出,以保持其整洁,但显然我没有尝试在运行测试时将其注释掉。对查看该代码但找不到问题的任何人表示抱歉。你是对的,问题不在于我提供的任何代码。

所以答案是,如果您尝试访问controllerNameoractionName变量,您可能会看到此处报告的异常。

解决方案是在执行任何可能引用or的过滤器之前使用 FiltersUnitTestCase 中的setControllerName()和方法。setActionName()controllerNameactionName

于 2011-10-10T03:18:34.153 回答