我正在运行Grails 2.3.7和Spring security 2.0-RC2。
我发现了与此主题相关的较旧帖子(2011)和JIRA报告 http://jira.grails.org/browse/GRAILS-7664
但是我不清楚它是否真的被修复了。我使用的表单有两个提交按钮(相当于g:actionSubmit)
<g:form style='margin: 0' controller="bankAccount">
<g:hiddenField name="id" value="${organizationRegisteredInstance?.bankAccount?.id}" />
<button type="submit" class="btn btn-xs btn-danger" name="_action_deleteMyBankAccount" >DELETE</button>
<button type="submit" class="btn btn-xs btn-warning" name="_action_editMyBankAccount" >EDIT</button>
</g:form>
出于测试目的,我试图与没有所需角色的用户调用这些链接。(@在控制器bankAccount中安全)。
Spring安全日志确实显示了AccessDeniedExeption,但Grails没有重定向到为403设置的错误页面。
如果我使用直接GET链接执行完全相同的操作,我会得到预期的行为,并且Grails重定向到URLMapping文件中定义的错误页面:
<g:link class="btn btn-xs btn-warning" controller="bankAccount" action="editMyBankAccount" id="${organizationRegisteredInstance?.bankAccount?.id}">
日志:
DEBUG Request '/bankaccount/index' matched by universal pattern '/**' DEBUG /bankAccount/index at position 1 of 9 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter' DEBUG Obtained a valid SecurityContext from SPRING_SECURITY_CONTEXT: 'org.springframework.security.core.context.SecurityContextImpl@57de70d6: Authentication: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@57de70d6: Principal: idr.IdrUser@17a81: Username: ass; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_NOT_ASSIGNED,ROLE_USER; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: null; Granted Authorities: ROLE_USER, ROLE_NOT_ASSIGNED' DEBUG /bankAccount/index at position 2 of 9 in additional filter chain; firing Filter: 'MutableLogoutFilter' DEBUG /bankAccount/index at position 3 of 9 in additional filter chain; firing Filter: 'RequestHolderAuthenticationFilter' DEBUG /bankAccount/index at position 4 of 9 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter' DEBUG /bankAccount/index at position 5 of 9 in additional filter chain; firing Filter: 'GrailsRememberMeAuthenticationFilter' DEBUG /bankAccount/index at position 6 of 9 in additional filter chain; firing Filter: 'GrailsAnonymousAuthenticationFilter' DEBUG /bankAccount/index at position 7 of 9 in additional filter chain; firing Filter: 'ExceptionTranslationFilter' DEBUG /bankAccount/index at position 8 of 9 in additional filter chain; firing Filter: 'FilterSecurityInterceptor' DEBUG Secure object: FilterInvocation: URL: /bankAccount/index; Attributes: [ROLE_ORG] DEBUG Previously Authenticated: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@57de70d6: Principal: idr.IdrUser@17a81: Username: ass; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_NOT_ASSIGNED,ROLE_USER; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: null; Granted Authorities: ROLE_USER, ROLE_NOT_ASSIGNED DEBUG getReachableGrantedAuthorities() - From the roles [ROLE_USER, ROLE_NOT_ASSIGNED] one can reach [ROLE_USER, ROLE_NOT_ASSIGNED] in zero or more steps. DEBUG Access is denied (user is not anonymous); delegating to AccessDeniedHandler org.springframework.security.access.AccessDeniedException: Access is denied at grails.plugin.springsecurity.access.vote.AuthenticatedVetoableDecisionManager.deny(AuthenticatedVetoableDecisionManager.java:113) at grails.plugin.springsecurity.access.vote.AuthenticatedVetoableDecisionManager.checkOtherVoters(AuthenticatedVetoableDecisionManager.java:105) at grails.plugin.springsecurity.access.vote.AuthenticatedVetoableDecisionManager.decide(AuthenticatedVetoableDecisionManager.java:44) at grails.plugin.springsecurity.web.filter.GrailsAnonymousAuthenticationFilter.doFilter(GrailsAnonymousAuthenticationFilter.java:53) at grails.plugin.springsecurity.web.authentication.RequestHolderAuthenticationFilter.doFilter(RequestHolderAuthenticationFilter.java:49) at grails.plugin.springsecurity.web.authentication.logout.MutableLogoutFilter.doFilter(MutableLogoutFilter.java:82) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) at java.lang.Thread.run(Thread.java:744) DEBUG SecurityContextHolder now cleared, as request processing completed DEBUG Request '/grails-errorhandler' matched by universal pattern '/**' DEBUG /grails-errorhandler at position 1 of 9 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter' DEBUG Obtained a valid SecurityContext from SPRING_SECURITY_CONTEXT: 'org.springframework.security.core.context.SecurityContextImpl@57de70d6: Authentication: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@57de70d6: Principal: idr.IdrUser@17a81: Username: ass; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_NOT_ASSIGNED,ROLE_USER; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: null; Granted Authorities: ROLE_USER, ROLE_NOT_ASSIGNED' DEBUG /grails-errorhandler at position 2 of 9 in additional filter chain; firing Filter: 'MutableLogoutFilter' DEBUG /grails-errorhandler at position 3 of 9 in additional filter chain; firing Filter: 'RequestHolderAuthenticationFilter' DEBUG /grails-errorhandler at position 4 of 9 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter' DEBUG /grails-errorhandler at position 5 of 9 in additional filter chain; firing Filter: 'GrailsRememberMeAuthenticationFilter' DEBUG /grails-errorhandler at position 6 of 9 in additional filter chain; firing Filter: 'GrailsAnonymousAuthenticationFilter' DEBUG /grails-errorhandler at position 7 of 9 in additional filter chain; firing Filter: 'ExceptionTranslationFilter' DEBUG /grails-errorhandler at position 8 of 9 in additional filter chain; firing Filter: 'FilterSecurityInterceptor' DEBUG /grails-errorhandler at position 9 of 9 in additional filter chain; firing Filter: 'SwitchUserFilter' DEBUG /grails-errorhandler reached end of additional filter chain; proceeding with original chain DEBUG Chain processed normally DEBUG SecurityContextHolder now cleared, as request processing completed
尽管在URLMapping中有以下设置:
"403"(controller: "login", action: "denied")
"404"(controller: "home", action: "http404")
"405"(controller: "home", action: "http405")
我只是在Chrome和Firefox中获得一个空白页面,在IE中显示一个明确的HTTP 403。 看起来Grails只是忽略了错误处理(错误页面设置)。
编辑:添加控制器操作的代码:
@Secured(['ROLE_ORG'])
def editMyBankAccount(BankAccount bankAccountInstance) {
log.debug "## bankAccount.editMyBankAccount ##"
log.debug params
def selectedRace
// Used to redirect to MyRace page if ID is provided
if (params?.race_id && params?.race_id!="") {
selectedRace = idr.Race.get(params.race_id)
}
if (!bankAccountInstance) {
notFound()
return
}
def org = springSecurityService.getCurrentUser().organization
// check if logged org is the same as the one having the bankAccount
if (org && org.bankAccount && org.bankAccount==bankAccountInstance) {
return [bankAccountInstance: bankAccountInstance, race_id: selectedRace?.id]
} else {
errorPage(message(code: 'organizationRegistered.mismatch.message', default:'TODO'))
return
}
}
和GSP代码:
<%@ page import="idr.BankAccount" %>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="layout" content="main" />
<g:set var="entityName" value="${message(code: 'bankAccount.label', default: 'BankAccount')}" />
<r:require modules="bootstrap"/>
<title><g:message code="default.create.label" args="[entityName]" /></title>
</head>
<content tag="topmenu">
<g:render template="/common/navMenuTop" model="[activeMenu:'myPrivateProfile_org']" />
</content>
<body>
<div class="container">
<div class="row">
<div class="col-12">
<legend><g:message code="organization.bankaccount.section" /> <i class="glyphicon glyphicon-pencil"></i></legend>
<g:if test="${flash.message}">
<div class="alert alert-info">${flash.message}</div>
</g:if>
<g:hasErrors bean="${bankAccountInstance}">
<div class="alert alert-danger">
<g:renderErrors bean="${bankAccountInstance}" as="list" />
</div>
</g:hasErrors>
</div>
</div>
<g:form role="form" controller="bankAccount" action="update" name="accountForm">
<fieldset>
<g:hiddenField name="id" value="${bankAccountInstance?.id}" />
<g:hiddenField name="version" value="${bankAccountInstance?.version}" />
<g:render template="form"/>
<div class="row">
<div class="col-lg-offset-2 col-md-offset-1 col-lg-4 col-md-4 col-sm-5">
<div class="form-group">
<g:if test="${race_id && race_id!=""}">
<g:link class="btn btn-default" controller="race" action="myRace" id="${race_id}" >${message(code: 'default.button.cancel.label', default: 'Cancel')}</g:link>
</g:if>
<g:else>
<g:link class="btn btn-default" controller="organizationRegistered" action="myPrivateProfile" >${message(code: 'default.button.cancel.label', default: 'Cancel')}</g:link>
</g:else>
<button type="submit" class="btn btn-success">${message(code: 'default.button.update.label', default: 'Update')}</button>
</div>
</div>
</div>
</fieldset>
</g:form>
</div> <!-- container -->
</body>
谢谢, 约翰