更新:我已将此问题更改为我遇到的具体问题。这是因为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来执行我的过滤器?
如果是这样的话:
为什么我遇到此异常?
答案 0 :(得分:1)
提醒所有人调试规则:继续删除代码,直到找到问题所在的确切行。即使很明显该行没有引起问题。因为:有时它实际上是。
作为调试工作的一部分,我的过滤器中包含以下代码:
println "controllerName = '${controllerName}', actionName = '${actionName}'"
这是直接在线之前:
request.accessAllowed = true
我已经把它从粘贴到这个问题的代码中拿出来试图保持整洁,但显然我没有尝试在运行测试时将其评论出来。对于那些查看该代码但无法找到问题的人,感到抱歉。你是对的,问题不在我提供的任何代码中。
答案是如果您尝试访问controllerName
或actionName
变量,则可能会看到此处报告的异常。
解决方案是在执行任何可能引用setControllerName()
或setActionName()
的过滤器之前,使用FiltersUnitTestCase中的controllerName
和actionName
方法。