Spring 3.1忽略了我的@Secured Annotations



好吧,我有另一个"Spring正在忽略我的@Secured注释"。我在这里和其他地方读过很多其他的解决方案,但似乎没有一个能解决我的问题。

我使用的是Netbeans 7.4测试版,以及Spring 3.1.1和Spring Security 3.1.4。

我有一个控制器,应该限制登录用户:

package my.phonedirectory.mvc.controllers;
import javax.annotation.Resource;
import org.apache.log4j.Logger;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import my.phonedirectory.mvc.services.PhoneDirectoryService;
import org.springframework.security.access.annotation.Secured;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
@Controller
public class IndexController {
    protected static void debug(String msg) {
        Logger logger = Logger.getLogger("Controller");
        System.out.println("Logger Category: " + logger.getParent().toString());
        logger.debug(new Object() { }.getClass().getEnclosingClass().getSimpleName() + ": " + msg);
    }
    @Resource(name="phoneDirectoryService")
    PhoneDirectoryService phoneDirectoryService;
    public void setPhoneDirectoryService(PhoneDirectoryService phoneDirectoryService) {
        this.phoneDirectoryService = phoneDirectoryService;
    }
    @RequestMapping("/index.html")
    @Secured("ROLE_USER")
    protected ModelAndView handleRequestInternal(HttpServletRequest request,
                                                 HttpServletResponse response)
            throws Exception {
        debug("handleRequestInternal");
        String username;

        SecurityContext sc = SecurityContextHolder.getContext();
        Authentication auth = sc.getAuthentication();
        if (auth == null) {
            username = "SecurityContextHolder.getAuthentication() returned NULL";
        } else {
            Object principal = auth.getPrincipal();
            if (principal == null) {
                username = "SecurityContextHolder.getAuthentication().getPrincipal() returned NULL";
            } else {
                if (principal instanceof User) {
                    User user = (User)principal;
                    debug("User logged in: " + user.getUsername());
                    username = user.getUsername();
                } else {
                    debug("No user logged in: " + principal.toString());
                    username = principal.toString();
                }
            }
        }

        ModelAndView mv = new ModelAndView("index");
        mv.addObject("message", "Hello " + username);        
        return mv;
    }
}

我的index.jsp文件是:

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
    "http://www.w3.org/TR/html4/loose.dtd">
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>Phone Directory</title>
    </head>
    <body>
        <h1> Welcome to the Phone Directory</h1>
    <h2><%= (String)request.getAttribute("message") %></h2>
    <p>
        To see the Phone Directory, click <a href="list.html">HERE</a>.
    </body>
</html>

当我加载localhost:8080/PhoneDirectory/index.html时,我得到:

 Welcome to the Phone Directory
Hello anonymousUser
To see the Phone Directory, click HERE. 

因此,正如您所看到的,它不会强制登录尝试,而是允许匿名用户访问应该由@Secured("ROLE_user")保护的方法。

当我为Spring Security启用调试日志记录时,这就是我的日志中显示的内容。。。

INFO: PhoneDirectory was successfully deployed in 5,899 milliseconds.
INFO: 16:15:25,889 DEBUG web.FilterChainProxy:337 - /index.html at position 1 of 10 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
INFO: 16:15:25,891 DEBUG context.HttpSessionSecurityContextRepository:139 - HttpSession returned null object for SPRING_SECURITY_CONTEXT
INFO: 16:15:25,891 DEBUG context.HttpSessionSecurityContextRepository:85 - No SecurityContext was available from the HttpSession: org.apache.catalina.session.StandardSessionFacade@36c63b9. A new one will be created.
INFO: 16:15:25,900 DEBUG web.FilterChainProxy:337 - /index.html at position 2 of 10 in additional filter chain; firing Filter: 'LogoutFilter'
INFO: 16:15:25,901 DEBUG web.FilterChainProxy:337 - /index.html at position 3 of 10 in additional filter chain; firing Filter: 'UsernamePasswordAuthenticationFilter'
INFO: 16:15:25,901 DEBUG web.FilterChainProxy:337 - /index.html at position 4 of 10 in additional filter chain; firing Filter: 'BasicAuthenticationFilter'
INFO: 16:15:25,902 DEBUG web.FilterChainProxy:337 - /index.html at position 5 of 10 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
INFO: 16:15:25,902 DEBUG web.FilterChainProxy:337 - /index.html at position 6 of 10 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
INFO: 16:15:25,904 DEBUG web.FilterChainProxy:337 - /index.html at position 7 of 10 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
INFO: 16:15:25,907 DEBUG authentication.AnonymousAuthenticationFilter:102 - Populated SecurityContextHolder with anonymous token: 'org.springframework.security.authentication.AnonymousAuthenticationToken@6faeba70: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@fffbcba8: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: 33784332ecf862dfef93485b8bbf; Granted Authorities: ROLE_ANONYMOUS'
INFO: 16:15:25,907 DEBUG web.FilterChainProxy:337 - /index.html at position 8 of 10 in additional filter chain; firing Filter: 'SessionManagementFilter'
INFO: 16:15:25,908 DEBUG web.FilterChainProxy:337 - /index.html at position 9 of 10 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
INFO: 16:15:25,908 DEBUG web.FilterChainProxy:337 - /index.html at position 10 of 10 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
INFO: 16:15:25,909 DEBUG intercept.FilterSecurityInterceptor:185 - Public object - authentication not attempted
INFO: 16:15:25,910 DEBUG web.FilterChainProxy:323 - /index.html reached end of additional filter chain; proceeding with original chain
INFO: Logger Category: org.apache.log4j.spi.RootLogger@3fb9f67a
INFO: 16:15:25,967 DEBUG Controller:32 - IndexController: handleRequestInternal
INFO: Logger Category: org.apache.log4j.spi.RootLogger@3fb9f67a
INFO: 16:15:25,968 DEBUG Controller:32 - IndexController: No user logged in: anonymousUser
INFO: 16:15:25,976 DEBUG support.DefaultListableBeanFactory:1498 - Invoking afterPropertiesSet() on bean with name 'index'
INFO: 16:15:25,993 DEBUG support.DefaultListableBeanFactory:245 - Returning cached instance of singleton bean 'org.springframework.security.methodSecurityMetadataSourceAdvisor'
INFO: 16:15:26,151 DEBUG context.HttpSessionSecurityContextRepository:269 - SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
INFO: 16:15:26,152 DEBUG context.HttpSessionSecurityContextRepository:269 - SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
INFO: 16:15:26,155 DEBUG access.ExceptionTranslationFilter:115 - Chain processed normally
INFO: 16:15:26,156 DEBUG context.SecurityContextPersistenceFilter:97 - SecurityContextHolder now cleared, as request processing completed

这是我的web.xml文件(注意:我已经将通常的applicationContext.xml和applicationContext-security.xml重命名为root-context.xml和root-security.xml):

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0"
         xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
                             http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
    <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>
    </filter-mapping>

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

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <servlet>
        <servlet-name>phoneDirectory</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>2</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>phoneDirectory</servlet-name>
        <url-pattern>*.html</url-pattern>
    </servlet-mapping>
    <session-config>
        <session-timeout>
            30
        </session-timeout>
    </session-config>
    <welcome-file-list>
        <welcome-file>redirect.jsp</welcome-file>
    </welcome-file-list>
</web-app>

我的root-context.xml文件:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
                           http://www.springframework.org/schema/aop
                           http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
                           http://www.springframework.org/schema/tx
                           http://www.springframework.org/schema/tx/spring-tx-3.1.xsd">


</beans>

我的root-security.xml文件:

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

    <global-method-security secured-annotations="enabled" />
    <http auto-config="true"
                 use-expressions="true"
                 access-denied-page="/PhoneDirectory/accessDenied" >

        <form-login
            login-page="/PhoneDirectory/login"
            authentication-failure-url="/PhoneDirectory/login?error=true"
            default-target-url="/PhoneDirectory/list"/>
        <logout
            invalidate-session="true"
            logout-success-url="/PhoneDirectory/login"
            logout-url="/PhoneDirectory/logout"/>
    </http>
    <authentication-manager>
         <authentication-provider user-service-ref="userDetailsService">
         </authentication-provider>
    </authentication-manager>
  <user-service id="userDetailsService">
     <user name="user" password="user_password" authorities="ROLE_USER, ROLE_ADMIN" />
     <user name="admin" password="admin_password" authorities="ROLE_USER" />
   </user-service>

</beans:beans>

还有我的phoneDirectory-servlet.xml文件:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:security="http://www.springframework.org/schema/security"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
                           http://www.springframework.org/schema/aop
                           http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
                           http://www.springframework.org/schema/tx
                           http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
                           http://www.springframework.org/schema/context
                           http://www.springframework.org/schema/context/spring-context-3.1.xsd
                           http://www.springframework.org/schema/security 
                           http://www.springframework.org/schema/security/spring-security-3.1.xsd">
    <security:global-method-security secured-annotations="enabled" />
    <bean id="appService"
          class="my.phonedirectory.mvc.services.PhoneDirectoryService">        
    </bean>
    <bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"/>
    <context:component-scan base-package="my.phonedirectory.mvc" />
    <bean id="viewResolver"
          class="org.springframework.web.servlet.view.InternalResourceViewResolver"
          p:prefix="/WEB-INF/jsp/"
          p:suffix=".jsp" />

</beans>

我知道主要的建议总是"把标签放在myApp-servlet.xml文件中,而不是顶级的applicationContext.xml(在我的例子中是root-context.xml)。但这并没有解决我的问题…

Spring似乎在正确处理@Resource(javax.annotation.Resource)注释方面存在问题。我们注意到资源的声明范围被忽略了。

解决方案是使用Autowired而不是Resource。您可以尝试以下操作:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
...
    @Autowired
    @Qualifier("phoneDirectoryService")
    PhoneDirectoryService phoneDirectoryService;

它可能与Spring Security+MVC注释有关非法参数异常

如果它解决了,请参阅解释。http://sergey-karpushin.blogspot.com/2012/10/spring-mvc-security-secured-annotation.html

您是否可以尝试在服务类(PhoneDirectoryService)中直接使用@secured annotation,并将PhoneDirectryService的bean移动到根应用程序上下文

最新更新