好的,我还有另一个“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,在我的示例中)。但这并没有解决我的问题。 ..