Spring Security - 我如何启用方法安全注释?

Posted

技术标签:

【中文标题】Spring Security - 我如何启用方法安全注释?【英文标题】:Spring Security - how I can enable Method Security annotations? 【发布时间】:2012-01-04 00:02:48 【问题描述】:

*** 上有很多类似的问题,但我找不到任何答案:(

我有 web.xml 之类的:

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>
        /WEB-INF/spring-security.xml
    </param-value>
</context-param>

<servlet>
    <servlet-name>spring</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/spring-web.xml</param-value>
    </init-param>
</servlet>

<servlet-mapping>
    <servlet-name>spring</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>FORWARD</dispatcher>
    <dispatcher>REQUEST</dispatcher>
</filter-mapping>

并尝试使用注释配置method security。正如我所见,它必须由&lt;sec:global-method-security pre-post-annotations="enabled"/&gt; 完成,与其他组件位于相同的上下文中,在我的情况下为spring-web.xml。所以我关注spring-web.xml

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:sec="http://www.springframework.org/schema/security"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
          http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
          http://www.springframework.org/schema/security
          http://www.springframework.org/schema/security/spring-security-3.0.xsd"
        default-autowire="byName">

    <context:component-scan base-package="com.cleanplates.apiserv"/>
    <sec:global-method-security pre-post-annotations="enabled"/>

</beans>

spring-security.xml:

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:sec="http://www.springframework.org/schema/security"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
          http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
          http://www.springframework.org/schema/security
          http://www.springframework.org/schema/security/spring-security-3.0.xsd">

    <bean id="springSecurityFilterChain" class="org.springframework.security.web.FilterChainProxy">
        <sec:filter-chain-map path-type="ant">
            <sec:filter-chain pattern="/**"
                              filters="
                                usernamePasswordProcessingFilter,
                                rememberMeFilter,
                                anonymousProcessingFilter,
                                exceptionTranslationFilter,
                                filterInvocationInterceptor"/>
        </sec:filter-chain-map>
    </bean>

    <bean id="accessDecisionManager" class="org.springframework.security.access.vote.AffirmativeBased">
        <property name="decisionVoters">
            <list>
                <bean class="org.springframework.security.access.vote.RoleVoter"/>
            </list>
        </property>
    </bean>

    <bean id="anonymousProcessingFilter"
          class="org.springframework.security.web.authentication.AnonymousAuthenticationFilter">
        <property name="key" value="********"/>
        <property name="userAttribute">
            <bean class="org.springframework.security.core.userdetails.memory.UserAttribute">
                <property name="authoritiesAsString">
                    <list>
                        <value>ROLE_ANONYMOUS</value>
                    </list>
                </property>
                <property name="password" value="none"/>
            </bean>
        </property>
    </bean>

    <bean id="usernamePasswordProcessingFilter" class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter">
        <property name="filterProcessesUrl" value="/auth/password"/>
        <property name="usernameParameter" value="username"/>
        <property name="passwordParameter" value="password"/>
        <property name="authenticationManager" ref="authenticationManager"/>
    </bean>

    <bean id="rememberMeFilter" class="org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter">
        <property name="rememberMeServices" ref="rememberMeServices"/>
        <property name="authenticationManager" ref="authenticationManager" />
    </bean>

    <bean id="rememberMeServices" class="org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices">
        <property name="userDetailsService" ref="myUserDetailsService"/>
        <property name="key" value="*******"/>
        <property name="alwaysRemember" value="true"/>
    </bean>

    <bean id="rememberMeAuthenticationProvider" class="org.springframework.security.authentication.RememberMeAuthenticationProvider">
        <property name="key" value="******"/>
    </bean>

    <bean id="exceptionTranslationFilter" class="org.springframework.security.web.access.ExceptionTranslationFilter">
        <property name="authenticationEntryPoint">
            <bean class="org.springframework.security.web.authentication.Http403ForbiddenEntryPoint"/>
        </property>
    </bean>

    <bean id="filterInvocationInterceptor"
        class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor">
        <property name="authenticationManager" ref="authenticationManager"/>
        <property name="securityMetadataSource">
            <sec:filter-security-metadata-source>
              <sec:intercept-url pattern="/**" access="ROLE_ANONYMOUS,ROLE_USER" method="GET"/>
              <sec:intercept-url pattern="/**" access="ROLE_ADMIN" method="POST"/>
              <sec:intercept-url pattern="/**" access="ROLE_ADMIN" method="PUT"/>
              <sec:intercept-url pattern="/**" access="ROLE_ADMIN" method="DELETE"/>
            </sec:filter-security-metadata-source>
        </property>
        <property name="accessDecisionManager" ref="accessDecisionManager"/>
    </bean>

    <bean id="authenticationManager" class="org.springframework.security.authentication.ProviderManager">
        <property name="providers">
            <list>
                <bean class="org.springframework.security.authentication.AnonymousAuthenticationProvider">
                    <property name="key" value="***"/>
                </bean>
                <bean class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
                    <property name="saltSource">
                        <bean class="org.springframework.security.authentication.dao.ReflectionSaltSource">
                            <property name="userPropertyToUse" value="salt"/>
                        </bean>
                    </property>
                    <property name="userDetailsService" ref="myUserDetailsService"/>
                    <property name="passwordEncoder" ref="passwordEncoder"/>
                </bean>
            </list>
        </property>
    </bean>

    <bean id="myUserDetailsService" class=".UserDetailsServiceImpl">
    </bean>

    <bean id="passwordEncoder" class="org.springframework.security.authentication.encoding.Md5PasswordEncoder">
    </bean>

</beans>

添加&lt;sec:global-method-security后所有控制器停止工作的问题。我在日志中有以下内容:

PageNotFound:noHandlerFound:947 - No mapping found for HTTP request with URI [/some/page] in DispatcherServlet with name 'spring'

当我删除这个global-security 元素时,一切正常。如果我将它添加到spring-security.xml - 没有任何变化。似乎没有使用它,因为任何人都可以访问带有@PreAuthorize("hasRole('ROLE_ADMIN')")(或任何其他角色)注释的方法。

PS 我正在使用 Spring 3.0.5.RELEASE 和 Spring Security 3.0.5.RELEASE

【问题讨论】:

您正在使用哪些其他框架/库,特别是在您的控制器上?你在部署什么? 当前示例部署在码头上。其实是jetty maven插件,app开头是mvn jetty:run 使用了很多库。 maven 说大约有 50 个库。似乎作为评论放在那里太多了:) 请把配置文件的相关部分贴出来 @ralph 我也添加了spring-security.xml 【参考方案1】:

启用&lt;sec:global-method-security&gt; 后,spring security 会为您的控制器创建代理。在这种情况下,spring-mvc 在 bean 上找不到像 @RequestMapping 这样的注释。如果你想在你的控制器上使用安全注解,你应该提取控制器的接口并在上面放置 mvc 注释。 Spring 文档包含以下说明:

注意: 当使用控制器接口(例如用于 AOP 代理)时,请确保始终将 all 您的映射注释 - 例如 @RequestMapping@SessionAttributes -在控制器接口上而不是在实现类上。

【讨论】:

哦,所以我需要为这个功能制作这个接口?好奇怪:(好的,谢谢,明白了 是的。不幸的是,基于 java 代理和 CGLIB 的经典 spring AOP 只有在你拥有所有由 spring 管理的带注释的 bean 的接口时才能正确使用注释,在其他情况下,可能存在类似这样的不同情况,那么注释配置将不起作用。跨度> 可以以其他方式进行操作,无需接口或基类。您可以设置proxy-target-class="true" 以确保使用CGLIB 代理而不是接口代理。您不能做的是期望接口代理在实现类上保留注释,例如 @RequestMapping

以上是关于Spring Security - 我如何启用方法安全注释?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Spring Boot 中在 Spring Security 级别启用 CORS [关闭]

如何在 Spring Boot 中使用 Spring Security 启用 CORS

如何使用 XML 使用 Spring Security Oauth2 启用 /oauth/check_token

如何解决在使用 Spring Boot 和 Spring Security 启用 CSRF 后无法正常工作的登录问题?

如何使用 Spring MVC 和 Spring Security 为资源处理程序启用 HTTP 缓存

使用 CSRF 登录后如何启用 Spring Security POST 重定向?