Rest Secured controller在Grails应用程序中返回403一个操作,但不返回另一个操作

Rest Secured controller在Grails应用程序中返回403一个操作,但不返回另一个操作,rest,grails,spring-security,url-mapping,Rest,Grails,Spring Security,Url Mapping,我的应用程序中有一个控制器,如下所示: @Secured(UserRoles.ROLE_USER) class ProjectController implements BaseController, SpringSecurityAware { ProjectService projectService def create(ProjectCommand command) { ... } def update(ProjectCommand c

我的应用程序中有一个控制器,如下所示:

@Secured(UserRoles.ROLE_USER)
class ProjectController implements BaseController, SpringSecurityAware {

    ProjectService projectService

    def create(ProjectCommand command) {
        ...
    }

    def update(ProjectCommand command) {
        Long projectId = params.id
        ...
    }
}
post "/v1/api/project" (controller: "project", action: "create")

put "/v1/api/project/$id" {
   controller = "project"
   action = "update"
   constraints {
       id(matches:/\\\d+/)
   }
}
其映射如下:

@Secured(UserRoles.ROLE_USER)
class ProjectController implements BaseController, SpringSecurityAware {

    ProjectService projectService

    def create(ProjectCommand command) {
        ...
    }

    def update(ProjectCommand command) {
        Long projectId = params.id
        ...
    }
}
post "/v1/api/project" (controller: "project", action: "create")

put "/v1/api/project/$id" {
   controller = "project"
   action = "update"
   constraints {
       id(matches:/\\\d+/)
   }
}
我正在使用带有自定义令牌存储的SpringSecurityREST。身份验证机制工作正常,因为它已经测试并运行了一段时间

当我发送创建项目的post请求时,一切正常。 然而,如果我试图更新项目,我得到403,甚至没有进入行动方法

我的请求如下所示:

PUT /v1/api/project/12 HTTP/1.1
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6Ik1qTTFPRGxETjBWR1FUQXlOa00wUkRoR056TkZSRGs1TlRFME1VVXlRa0ZDT0VFelJUazBRdyJ9....0qS2PUw8PQ
Content-Type: application/x-www-form-urlencoded; charset=utf-8
Cookie: JSESSIONID=61F4874A906D706062C0209CEBF2AC3E
Host: localhost:8080
Connection: close
User-Agent: Paw/3.1.7 (Macintosh; OS X/10.13.5) GCDHTTPRequest
Content-Length: 77

title=Project+Update&background=Background&problemStatement=Problem+Statement
注:

  • UserRoles.ROLE\u USER
    是一个简单的字符串
  • 如果我正在调试请求,则解析的用户确实具有预期的权限
  • 我错过了什么? 我怀疑UrlMapping有问题

    更新 这是调试日志。。。这对我来说没有多大意义。看起来它的身份验证是正确的,但是在最后,角色是不允许的,即使它是正确的角色

    2018-07-03 01:14:59.665 DEBUG --- [nio-8080-exec-4] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/v1/api/project/12'; against '/v1/login'
    2018-07-03 01:14:59.665 DEBUG --- [nio-8080-exec-4] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/v1/api/project/12'; against '/v1/api/**'
    2018-07-03 01:14:59.667 DEBUG --- [nio-8080-exec-4] o.s.security.web.FilterChainProxy        : /v1/api/project/12 at position 1 of 7 in additional filter chain; firing Filter: 'SecurityRequestHolderFilter'
    2018-07-03 01:14:59.674 DEBUG --- [nio-8080-exec-4] o.s.security.web.FilterChainProxy        : /v1/api/project/12 at position 2 of 7 in additional filter chain; firing Filter: 'MutableLogoutFilter'
    2018-07-03 01:14:59.675 DEBUG --- [nio-8080-exec-4] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/v1/api/project/12'; against '/logoff'
    2018-07-03 01:14:59.675 DEBUG --- [nio-8080-exec-4] o.s.security.web.FilterChainProxy        : /v1/api/project/12 at position 3 of 7 in additional filter chain; firing Filter: 'RestAuthenticationFilter'
    2018-07-03 01:14:59.675 DEBUG --- [nio-8080-exec-4] g.p.s.rest.RestAuthenticationFilter      : Actual URI is /v1/api/project/12; endpoint URL is /api/login
    2018-07-03 01:14:59.675 DEBUG --- [nio-8080-exec-4] o.s.security.web.FilterChainProxy        : /v1/api/project/12 at position 4 of 7 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
    2018-07-03 01:14:59.681 DEBUG --- [nio-8080-exec-4] o.s.security.web.FilterChainProxy        : /v1/api/project/12 at position 5 of 7 in additional filter chain; firing Filter: 'RestTokenValidationFilter'
    2018-07-03 01:14:59.690 DEBUG --- [nio-8080-exec-4] g.p.s.r.token.bearer.BearerTokenReader   : Looking for bearer token in Authorization header, query string or Form-Encoded body parameter
    2018-07-03 01:14:59.690 DEBUG --- [nio-8080-exec-4] g.p.s.r.token.bearer.BearerTokenReader   : Found bearer token in Authorization header
    2018-07-03 01:14:59.690 DEBUG --- [nio-8080-exec-4] g.p.s.r.token.bearer.BearerTokenReader   : Token: eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6Ik1qTTFPRGxETjBWR1FUQXlOa00wUkRoR056TkZSRGs1TlRFME1VVXlRa0ZDT0VFelJUazBRdyJ9.eyJpc3MiOiJodHRwczovL3ByaXotZGV2LmF1dGgwLmNvbS8iLCJzdWIiOiJnb29nbGUtb2F1dGgyfDEwNjY0NzgyMTY3NjY0Mzk5ODE2MCIsImF1ZCI6WyJodHRwczovL3ByaXotZGV2LmF1dGgwLmNvbS9hcGkvdjIvIiwiaHR0cHM6Ly9wcml6LWRldi5hdXRoMC5jb20vdXNlcmluZm8iXSwiaWF0IjoxNTMwNjA1NjU5LCJleHAiOjE1MzA2MTI4NTksImF6cCI6ImtXcnJTT2Nsam1xM3dHTDB1SXR6ZVZ0ZjBMdzdidnlMIiwic2NvcGUiOiJvcGVuaWQgcHJvZmlsZSBlbWFpbCJ9.Oybu4Y4JKhWxuBBWST4f7bqge6AXxvx6wREkhU5OfA8WiR5vJ9Jd8NwjbsdfBss8A4ECjmsDTJb7yCT7nWlr0BAdimhcM6-hU_RtOEl8u_zxPnJrT4I58m_j2eWjoyGCa2snwnBwX1F49ls75bBeH_SEgd4pFanptfUCI2_UluqmvBnSuq_v5bGcB87k0OCcfXR_sZs8Cj_Llt-pgf8yYYisX8EBwfyTm6DeHcSgYPQedGY5zORuZ5T6jlpx3xJwc8J3MrXXUyTRvvZPy7mzyyd12Yfjmh2qrFZ_yFY9yaJVAMtZheLAT0GiamrRtLwL6AcQ-zdJqZJ6ik_4nLPw8g
    2018-07-03 01:14:59.699 DEBUG --- [nio-8080-exec-4] g.p.s.rest.RestTokenValidationFilter     : Token found: eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6Ik1qTTFPRGxETjBWR1FUQXlOa00wUkRoR056TkZSRGs1TlRFME1VVXlRa0ZDT0VFelJUazBRdyJ9.eyJpc3MiOiJodHRwczovL3ByaXotZGV2LmF1dGgwLmNvbS8iLCJzdWIiOiJnb29nbGUtb2F1dGgyfDEwNjY0NzgyMTY3NjY0Mzk5ODE2MCIsImF1ZCI6WyJodHRwczovL3ByaXotZGV2LmF1dGgwLmNvbS9hcGkvdjIvIiwiaHR0cHM6Ly9wcml6LWRldi5hdXRoMC5jb20vdXNlcmluZm8iXSwiaWF0IjoxNTMwNjA1NjU5LCJleHAiOjE1MzA2MTI4NTksImF6cCI6ImtXcnJTT2Nsam1xM3dHTDB1SXR6ZVZ0ZjBMdzdidnlMIiwic2NvcGUiOiJvcGVuaWQgcHJvZmlsZSBlbWFpbCJ9.Oybu4Y4JKhWxuBBWST4f7bqge6AXxvx6wREkhU5OfA8WiR5vJ9Jd8NwjbsdfBss8A4ECjmsDTJb7yCT7nWlr0BAdimhcM6-hU_RtOEl8u_zxPnJrT4I58m_j2eWjoyGCa2snwnBwX1F49ls75bBeH_SEgd4pFanptfUCI2_UluqmvBnSuq_v5bGcB87k0OCcfXR_sZs8Cj_Llt-pgf8yYYisX8EBwfyTm6DeHcSgYPQedGY5zORuZ5T6jlpx3xJwc8J3MrXXUyTRvvZPy7mzyyd12Yfjmh2qrFZ_yFY9yaJVAMtZheLAT0GiamrRtLwL6AcQ-zdJqZJ6ik_4nLPw8g
    2018-07-03 01:14:59.699 DEBUG --- [nio-8080-exec-4] g.p.s.rest.RestTokenValidationFilter     : Trying to authenticate the token
    2018-07-03 01:14:59.699 DEBUG --- [nio-8080-exec-4] g.p.s.rest.RestAuthenticationProvider    : Use JWT: false
    2018-07-03 01:14:59.699 DEBUG --- [nio-8080-exec-4] g.p.s.rest.RestAuthenticationProvider    : Trying to validate token eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6Ik1qTTFPRGxETjBWR1FUQXlOa00wUkRoR056TkZSRGs1TlRFME1VVXlRa0ZDT0VFelJUazBRdyJ9.eyJpc3MiOiJodHRwczovL3ByaXotZGV2LmF1dGgwLmNvbS8iLCJzdWIiOiJnb29nbGUtb2F1dGgyfDEwNjY0NzgyMTY3NjY0Mzk5ODE2MCIsImF1ZCI6WyJodHRwczovL3ByaXotZGV2LmF1dGgwLmNvbS9hcGkvdjIvIiwiaHR0cHM6Ly9wcml6LWRldi5hdXRoMC5jb20vdXNlcmluZm8iXSwiaWF0IjoxNTMwNjA1NjU5LCJleHAiOjE1MzA2MTI4NTksImF6cCI6ImtXcnJTT2Nsam1xM3dHTDB1SXR6ZVZ0ZjBMdzdidnlMIiwic2NvcGUiOiJvcGVuaWQgcHJvZmlsZSBlbWFpbCJ9.Oybu4Y4JKhWxuBBWST4f7bqge6AXxvx6wREkhU5OfA8WiR5vJ9Jd8NwjbsdfBss8A4ECjmsDTJb7yCT7nWlr0BAdimhcM6-hU_RtOEl8u_zxPnJrT4I58m_j2eWjoyGCa2snwnBwX1F49ls75bBeH_SEgd4pFanptfUCI2_UluqmvBnSuq_v5bGcB87k0OCcfXR_sZs8Cj_Llt-pgf8yYYisX8EBwfyTm6DeHcSgYPQedGY5zORuZ5T6jlpx3xJwc8J3MrXXUyTRvvZPy7mzyyd12Yfjmh2qrFZ_yFY9yaJVAMtZheLAT0GiamrRtLwL6AcQ-zdJqZJ6ik_4nLPw8g
    2018-07-03 01:14:59.873 DEBUG --- [nio-8080-exec-4] g.p.s.rest.RestAuthenticationProvider    : Authentication result: grails.plugin.springsecurity.rest.token.AccessToken(accessToken:eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6Ik1qTTFPRGxETjBWR1FUQXlOa00wUkRoR056TkZSRGs1TlRFME1VVXlRa0ZDT0VFelJUazBRdyJ9.eyJpc3MiOiJodHRwczovL3ByaXotZGV2LmF1dGgwLmNvbS8iLCJzdWIiOiJnb29nbGUtb2F1dGgyfDEwNjY0NzgyMTY3NjY0Mzk5ODE2MCIsImF1ZCI6WyJodHRwczovL3ByaXotZGV2LmF1dGgwLmNvbS9hcGkvdjIvIiwiaHR0cHM6Ly9wcml6LWRldi5hdXRoMC5jb20vdXNlcmluZm8iXSwiaWF0IjoxNTMwNjA1NjU5LCJleHAiOjE1MzA2MTI4NTksImF6cCI6ImtXcnJTT2Nsam1xM3dHTDB1SXR6ZVZ0ZjBMdzdidnlMIiwic2NvcGUiOiJvcGVuaWQgcHJvZmlsZSBlbWFpbCJ9.Oybu4Y4JKhWxuBBWST4f7bqge6AXxvx6wREkhU5OfA8WiR5vJ9Jd8NwjbsdfBss8A4ECjmsDTJb7yCT7nWlr0BAdimhcM6-hU_RtOEl8u_zxPnJrT4I58m_j2eWjoyGCa2snwnBwX1F49ls75bBeH_SEgd4pFanptfUCI2_UluqmvBnSuq_v5bGcB87k0OCcfXR_sZs8Cj_Llt-pgf8yYYisX8EBwfyTm6DeHcSgYPQedGY5zORuZ5T6jlpx3xJwc8J3MrXXUyTRvvZPy7mzyyd12Yfjmh2qrFZ_yFY9yaJVAMtZheLAT0GiamrRtLwL6AcQ-zdJqZJ6ik_4nLPw8g, accessTokenJwt:null, expiration:null, refreshToken:null, refreshTokenJwt:null, principal:grails.plugin.springsecurity.userdetails.GrailsUser@2dba1e: Username: alex; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_USER, super:grails.plugin.springsecurity.rest.token.AccessToken@4430b82e: Principal: grails.plugin.springsecurity.userdetails.GrailsUser@2dba1e: Username: alex; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_USER; Credentials: [PROTECTED]; Authenticated: true; Details: null; Granted Authorities: ROLE_USER)
    2018-07-03 01:14:59.873 DEBUG --- [nio-8080-exec-4] g.p.s.rest.RestTokenValidationFilter     : Token authenticated. Storing the authentication result in the security context
    2018-07-03 01:14:59.873 DEBUG --- [nio-8080-exec-4] g.p.s.rest.RestTokenValidationFilter     : Authentication result: grails.plugin.springsecurity.rest.token.AccessToken(accessToken:eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6Ik1qTTFPRGxETjBWR1FUQXlOa00wUkRoR056TkZSRGs1TlRFME1VVXlRa0ZDT0VFelJUazBRdyJ9.eyJpc3MiOiJodHRwczovL3ByaXotZGV2LmF1dGgwLmNvbS8iLCJzdWIiOiJnb29nbGUtb2F1dGgyfDEwNjY0NzgyMTY3NjY0Mzk5ODE2MCIsImF1ZCI6WyJodHRwczovL3ByaXotZGV2LmF1dGgwLmNvbS9hcGkvdjIvIiwiaHR0cHM6Ly9wcml6LWRldi5hdXRoMC5jb20vdXNlcmluZm8iXSwiaWF0IjoxNTMwNjA1NjU5LCJleHAiOjE1MzA2MTI4NTksImF6cCI6ImtXcnJTT2Nsam1xM3dHTDB1SXR6ZVZ0ZjBMdzdidnlMIiwic2NvcGUiOiJvcGVuaWQgcHJvZmlsZSBlbWFpbCJ9.Oybu4Y4JKhWxuBBWST4f7bqge6AXxvx6wREkhU5OfA8WiR5vJ9Jd8NwjbsdfBss8A4ECjmsDTJb7yCT7nWlr0BAdimhcM6-hU_RtOEl8u_zxPnJrT4I58m_j2eWjoyGCa2snwnBwX1F49ls75bBeH_SEgd4pFanptfUCI2_UluqmvBnSuq_v5bGcB87k0OCcfXR_sZs8Cj_Llt-pgf8yYYisX8EBwfyTm6DeHcSgYPQedGY5zORuZ5T6jlpx3xJwc8J3MrXXUyTRvvZPy7mzyyd12Yfjmh2qrFZ_yFY9yaJVAMtZheLAT0GiamrRtLwL6AcQ-zdJqZJ6ik_4nLPw8g, accessTokenJwt:null, expiration:null, refreshToken:null, refreshTokenJwt:null, principal:grails.plugin.springsecurity.userdetails.GrailsUser@2dba1e: Username: alex; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_USER, super:grails.plugin.springsecurity.rest.token.AccessToken@4430b82e: Principal: grails.plugin.springsecurity.userdetails.GrailsUser@2dba1e: Username: alex; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_USER; Credentials: [PROTECTED]; Authenticated: true; Details: null; Granted Authorities: ROLE_USER)
    2018-07-03 01:14:59.873 DEBUG --- [nio-8080-exec-4] g.p.s.rest.RestTokenValidationFilter     : Continuing the filter chain
    2018-07-03 01:14:59.878 DEBUG --- [nio-8080-exec-4] o.s.security.web.FilterChainProxy        : /v1/api/project/12 at position 6 of 7 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
    2018-07-03 01:14:59.878 DEBUG --- [nio-8080-exec-4] o.s.security.web.FilterChainProxy        : /v1/api/project/12 at position 7 of 7 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
    2018-07-03 01:14:59.977 DEBUG --- [nio-8080-exec-4] o.s.s.w.a.i.FilterSecurityInterceptor    : Secure object: FilterInvocation: URL: /v1/api/project/12; Attributes: [_DENY_]
    2018-07-03 01:14:59.978 DEBUG --- [nio-8080-exec-4] o.s.s.w.a.i.FilterSecurityInterceptor    : Previously Authenticated: grails.plugin.springsecurity.rest.token.AccessToken(accessToken:eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6Ik1qTTFPRGxETjBWR1FUQXlOa00wUkRoR056TkZSRGs1TlRFME1VVXlRa0ZDT0VFelJUazBRdyJ9.eyJpc3MiOiJodHRwczovL3ByaXotZGV2LmF1dGgwLmNvbS8iLCJzdWIiOiJnb29nbGUtb2F1dGgyfDEwNjY0NzgyMTY3NjY0Mzk5ODE2MCIsImF1ZCI6WyJodHRwczovL3ByaXotZGV2LmF1dGgwLmNvbS9hcGkvdjIvIiwiaHR0cHM6Ly9wcml6LWRldi5hdXRoMC5jb20vdXNlcmluZm8iXSwiaWF0IjoxNTMwNjA1NjU5LCJleHAiOjE1MzA2MTI4NTksImF6cCI6ImtXcnJTT2Nsam1xM3dHTDB1SXR6ZVZ0ZjBMdzdidnlMIiwic2NvcGUiOiJvcGVuaWQgcHJvZmlsZSBlbWFpbCJ9.Oybu4Y4JKhWxuBBWST4f7bqge6AXxvx6wREkhU5OfA8WiR5vJ9Jd8NwjbsdfBss8A4ECjmsDTJb7yCT7nWlr0BAdimhcM6-hU_RtOEl8u_zxPnJrT4I58m_j2eWjoyGCa2snwnBwX1F49ls75bBeH_SEgd4pFanptfUCI2_UluqmvBnSuq_v5bGcB87k0OCcfXR_sZs8Cj_Llt-pgf8yYYisX8EBwfyTm6DeHcSgYPQedGY5zORuZ5T6jlpx3xJwc8J3MrXXUyTRvvZPy7mzyyd12Yfjmh2qrFZ_yFY9yaJVAMtZheLAT0GiamrRtLwL6AcQ-zdJqZJ6ik_4nLPw8g, accessTokenJwt:null, expiration:null, refreshToken:null, refreshTokenJwt:null, principal:grails.plugin.springsecurity.userdetails.GrailsUser@2dba1e: Username: alex; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_USER, super:grails.plugin.springsecurity.rest.token.AccessToken@4430b82e: Principal: grails.plugin.springsecurity.userdetails.GrailsUser@2dba1e: Username: alex; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_USER; Credentials: [PROTECTED]; Authenticated: true; Details: null; Granted Authorities: ROLE_USER)
    2018-07-03 01:14:59.979 DEBUG --- [nio-8080-exec-4] o.s.s.a.h.RoleHierarchyImpl              : getReachableGrantedAuthorities() - From the roles [ROLE_USER] one can reach [ROLE_USER] in zero or more steps.
    2018-07-03 01:14:59.997 DEBUG --- [nio-8080-exec-4] o.s.s.w.a.ExceptionTranslationFilter     : Access is denied (user is not anonymous); delegating to AccessDeniedHandler
    
    org.springframework.security.access.AccessDeniedException: Access is denied
        at org.springframework.security.access.vote.AbstractAccessDecisionManager.checkAllowIfAllAbstainDecisions(AbstractAccessDecisionManager.java:70)
        at grails.plugin.springsecurity.access.vote.AuthenticatedVetoableDecisionManager.decide(AuthenticatedVetoableDecisionManager.groovy:50)
        at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:233)
        at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:124)
        at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:91)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
        at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:114)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
        at javax.servlet.FilterChain$doFilter.call(Unknown Source)
        at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:136)
        at grails.plugin.springsecurity.rest.RestTokenValidationFilter.processFilterChain(RestTokenValidationFilter.groovy:121)
        at grails.plugin.springsecurity.rest.RestTokenValidationFilter.doFilter(RestTokenValidationFilter.groovy:87)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
        at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:170)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
        at grails.plugin.springsecurity.rest.RestAuthenticationFilter.doFilter(RestAuthenticationFilter.groovy:139)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
        at grails.plugin.springsecurity.web.authentication.logout.MutableLogoutFilter.doFilter(MutableLogoutFilter.groovy:64)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
        at grails.plugin.springsecurity.web.SecurityRequestHolderFilter.doFilter(SecurityRequestHolderFilter.groovy:58)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
        at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:214)
        at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:177)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.grails.web.servlet.mvc.GrailsWebRequestFilter.doFilterInternal(GrailsWebRequestFilter.java:77)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.grails.web.filters.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:67)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:96)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.springframework.boot.actuate.autoconfigure.MetricsFilter.doFilterInternal(MetricsFilter.java:106)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
        at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:496)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81)
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342)
        at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:803)
        at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
        at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:790)
        at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1459)
        at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
        at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
        at java.lang.Thread.run(Thread.java:745)
    
    2018-07-03 01:15:00.005 DEBUG --- [nio-8080-exec-4] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/error'; against '/v1/login'
    2018-07-03 01:15:00.005 DEBUG --- [nio-8080-exec-4] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/error'; against '/v1/api/**'
    2018-07-03 01:15:00.005 DEBUG --- [nio-8080-exec-4] o.s.security.web.FilterChainProxy        : /error has no matching filters
    

    显然,这个问题根本与安全无关。 问题在于UrlMapping

    更新的URL映射应为:

    put "/v1/api/project/$id" {
       controller = "project"
       action = "update"
       constraints {
           id(matches:/\d+/)
       }
    }
    
    约束的正则表达式是错误的


    但是,我仍然不明白为什么返回403而不是404。

    要调试SpringSecuyrity的运行情况,请将调试日志添加到您的配置中,否则可能是猜测:另外,请确保您没有任何过滤器阻止本地主机环境中的请求。您可以逐个剥离更新操作的UrlMapping,并在每次更改后重复该请求,以查看提供更新操作的URL映射是什么403@TuomasValtonen我添加了日志的输出