使用 Spring Security 3.2.4 for Jersey 2.9 REST 服务的全局方法安全性的正确配置是啥?

Posted

技术标签:

【中文标题】使用 Spring Security 3.2.4 for Jersey 2.9 REST 服务的全局方法安全性的正确配置是啥?【英文标题】:What are the right configurations for global method security with Spring Security 3.2.4 for Jersey 2.9 REST services?使用 Spring Security 3.2.4 for Jersey 2.9 REST 服务的全局方法安全性的正确配置是什么? 【发布时间】:2014-07-29 06:05:02 【问题描述】:

我正在尝试将我的 Jersey REST 服务配置为使用 Spring 提供的全局方法安全性来保护。我想我在整个画面中遗漏了一些东西。这是我的代码片段:

我的安全配置类(我试图纯粹在 java 代码中执行此操作,问题之一是大多数示例都使用 .xml 配置):

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class GlobalMethodSecurityConfig extends WebSecurityConfigurerAdapter 

    @Override
    protected void configure(AuthenticationManagerBuilder auth)
            throws Exception 
        auth.inMemoryAuthentication().withUser("user").password("password")
                .roles("USER");
    

    @Override
    protected void configure(HttpSecurity http) throws Exception 
        http.authorizeRequests().anyRequest().permitAll();
    

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception 
        return super.authenticationManagerBean();
    

网络安全通过以下方式初始化:

public class WebSecurityInitializer extends
        AbstractSecurityWebApplicationInitializer 

(这其实和在web.xml中添加spring过滤器是一样的)

带有注释@PreAuthorized("permitAll") 的方法被正确打开。但是当我打开一个映射到带有@PreAuthorized("hasRole('ROLE_USER')") 注释的方法的 URL 时,我得到了这个异常:

java.lang.IllegalStateException: Cannot create a session after the response has been committed
    org.apache.catalina.connector.Request.doGetSession(Request.java:2934)
    org.apache.catalina.connector.Request.getSession(Request.java:2310)
    org.apache.catalina.connector.RequestFacade.getSession(RequestFacade.java:897)
    org.apache.catalina.connector.RequestFacade.getSession(RequestFacade.java:909)
    javax.servlet.http.HttpServletRequestWrapper.getSession(HttpServletRequestWrapper.java:238)
    javax.servlet.http.HttpServletRequestWrapper.getSession(HttpServletRequestWrapper.java:238)
    javax.servlet.http.HttpServletRequestWrapper.getSession(HttpServletRequestWrapper.java:238)
    org.springframework.security.web.savedrequest.HttpSessionRequestCache.saveRequest(HttpSessionRequestCache.java:40)
    org.springframework.security.web.access.ExceptionTranslationFilter.sendStartAuthentication(ExceptionTranslationFilter.java:184)
    org.springframework.security.web.access.ExceptionTranslationFilter.handleSpringSecurityException(ExceptionTranslationFilter.java:168)
    org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:131)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:103)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:113)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:154)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:45)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:110)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    org.springframework.security.web.csrf.CsrfFilter.doFilterInternal(CsrfFilter.java:85)
    org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:57)
    org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:50)
    org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192)
    org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160)
    org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:344)
    org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:261)

【问题讨论】:

此异常可能是症状,而不是原因。提交的请求意味着某些内容已经发送到浏览器(客户端)。你能用萤火虫检查发送的内容吗? 【参考方案1】:

您收到异常是因为 spring security 的 @PreAuthorized("hasRole('ROLE_USER')") 注释中的 "hasRole('ROLE_USER')" 是由 SecurityExpressionRoot 实现的表达式。它默认返回false。 您可能必须为 SecurityExpressionRoot 添加自定义实现并覆盖“hasRole”方法。更多详情请参考:http://docs.spring.io/spring-security/site/docs/3.0.x/reference/el-access.html 我希望这会有所帮助!

【讨论】:

【参考方案2】:

我也没有运气扩展AbstractSecurityWebApplicationInitializer,尽管以下似乎对我有用:

public class WebApplicationConfiguration extends AbstractAnnotationConfigDispatcherServletInitializer 

    @Override
    public void onStartup(ServletContext servletContext) throws ServletException 
        super.onStartup(servletContext);

        servletContext.addFilter("springSecurityFilterChain", DelegatingFilterProxy.class)
                .addMappingForUrlPatterns(EnumSet.<DispatcherType>of(DispatcherType.REQUEST, DispatcherType.ERROR, DispatcherType.ASYNC), false, "/*");
    

    @Override
    protected Class<?>[] getRootConfigClasses() 
        return new Class<?>[] 
                GlobalMethodSecurityConfig.class,
                // other java config classes come here
        ;
    

    @Override
    protected Class<?>[] getServletConfigClasses() 
        return null;
    

    @Override
    protected String[] getServletMappings() 
        return null;
    


【讨论】:

以上是关于使用 Spring Security 3.2.4 for Jersey 2.9 REST 服务的全局方法安全性的正确配置是啥?的主要内容,如果未能解决你的问题,请参考以下文章

添加 Spring Security 插件 3.1.1 后,Grails 3.2.4 应用程序不会加载

Spring Security 应用程序中的 Sitemesh 未装饰自定义错误页面

Grails 3.2.4:未调用自定义身份验证过滤器

Spring Framework,Spring Security - 可以在没有 Spring Framework 的情况下使用 Spring Security?

DaoAuthenticationProvider 不允许使用相同的凭据重新登录

仅使用 Spring-Security(或)Spring 进行授权