Spring 3.1忽略了我的@Secured Annotations

时间:2013-08-06 11:00:52

标签: spring-mvc spring-security

好的,我还有另一个“Spring正在忽略我的@Secured注释”。我已经在这里和其他地方阅读了其他一些解决方案,似乎没有解决我的问题。

我正在使用Netbeans 7.4beta,以及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)。但是这并没有解决我的问题......

3 个答案:

答案 0 :(得分:1)

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;

答案 1 :(得分:0)

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

答案 2 :(得分:0)