我正在尝试通过Scarioni的“Pro Spring Security”实现一个示例,该示例实现了一个自定义内存用户模型(实现UserDetailsService接口)和自定义表达式处理程序。当我尝试登录时,我的CustomInMemoryUserDetailsManager的loadUserByUsername()方法将传递一个空白(非空)字符串作为用户名。这导致拒绝访问。如果我强制用户名是预期的(管理员),一切正常,包括自定义表达式处理。
这是我的安全配置:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:security="http://www.springframework.org/schema/security"
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">
<security:http auto-config="true" use-expressions="true" >
<security:expression-handler ref="expressionHandler" />
<security:intercept-url pattern="/admin/*" access="hasRole('ROLE_ADMIN') and hasIpAddress('127.0.0.1') and over18"/>
<security:remember-me key="terror-key" />
<security:form-login login-page="/custom_login"
authentication-failure-handler-ref="serverErrorHandler"
username-parameter="user_param" password-parameter="pass_param" />
</security:http>
<security:authentication-manager>
<security:authentication-provider user-service-ref="inMemoryUserServiceWithCustomUser" />
</security:authentication-manager>
<!-- Custom expression handler bean -->
<bean id="expressionHandler" class="com.apress.pss.terrormovies.security.CustomWebSecurityExpressionHandler"/>
<bean id="inMemoryUserServiceWithCustomUser"
class="com.apress.pss.terrormovies.spring.CustomInMemoryUserDetailsManager">
<constructor-arg>
<list>
<bean class="com.apress.pss.terrormovies.model.User">
<constructor-arg value="admin"/>
<constructor-arg value="admin"/>
<constructor-arg>
<list>
<bean class="org.springframework.security.core.authority.SimpleGrantedAuthority">
<constructor-arg value="ROLE_ADMIN"/>
</bean>
</list>
</constructor-arg>
<constructor-arg value="Scarioni"/>
<constructor-arg value="19"/>
</bean>
</list>
</constructor-arg>
</bean>
<bean id="logoutRedirectToAny"
class="org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler">
</bean>
<bean id="serverErrorHandler" class="com.apress.pss.terrormovies.security.ServerErrorFailureHandler"/>
</beans>
这是我的CustomInMemoryUserDetailsManager类:
package com.apress.pss.terrormovies.spring;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.apress.pss.terrormovies.model.User;
public class CustomInMemoryUserDetailsManager implements UserDetailsService {
private final Log logger = LogFactory.getLog(getClass());
private Map<String, User> users = new HashMap<String, User>();
public CustomInMemoryUserDetailsManager(Collection<User> users) {
for (User user : users) {
this.users.put(user.getUsername().toLowerCase(), user);
logger.debug("CustomInMemoryUserDetailsManager()- put username: " +
user.getUsername() + " last name: " + user.getLastName() + " authority: " +
user.getAuthorities());
}
}
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
// Test - force user name to that expected
//username = "admin";
if (username.equals("")) logger.debug("loadUserByUsername()- username is blank!!!");
logger.debug("loadUserByUsername()- username: " + username);
User user = users.get(username.toLowerCase());
if (user == null) {
throw new UsernameNotFoundException(username);
}
logger.debug("loadUserByUsername()- found " + user.getUsername());
User userNew = new User(user.getUsername(), user.getPassword(),
user.getAuthorities(), user.getLastName(), user.getAge());
return userNew;
}
}
我打开了Spring调试并获得了一个非常大的日志,这是我认为从登录到j_spring_security_check的相关部分:
:28,785 DEBUG main DispatcherServlet:130 - Servlet 'terrormovies' configured successfully
08:29:48,058 DEBUG qtp1624348237-15 FilterChainProxy:337 - /admin/movies at position 1 of 11 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
08:29:48,072 DEBUG qtp1624348237-15 HttpSessionSecurityContextRepository:127 - No HttpSession currently exists
08:29:48,085 DEBUG qtp1624348237-15 HttpSessionSecurityContextRepository:85 - No SecurityContext was available from the HttpSession: null. A new one will be created.
08:29:48,120 DEBUG qtp1624348237-15 FilterChainProxy:337 - /admin/movies at position 2 of 11 in additional filter chain; firing Filter: 'LogoutFilter'
08:29:48,120 DEBUG qtp1624348237-15 FilterChainProxy:337 - /admin/movies at position 3 of 11 in additional filter chain; firing Filter: 'UsernamePasswordAuthenticationFilter'
08:29:48,120 DEBUG qtp1624348237-15 FilterChainProxy:337 - /admin/movies at position 4 of 11 in additional filter chain; firing Filter: 'BasicAuthenticationFilter'
08:29:48,121 DEBUG qtp1624348237-15 FilterChainProxy:337 - /admin/movies at position 5 of 11 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
08:29:48,121 DEBUG qtp1624348237-15 FilterChainProxy:337 - /admin/movies at position 6 of 11 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
08:29:48,122 DEBUG qtp1624348237-15 FilterChainProxy:337 - /admin/movies at position 7 of 11 in additional filter chain; firing Filter: 'RememberMeAuthenticationFilter'
08:29:48,123 DEBUG qtp1624348237-15 FilterChainProxy:337 - /admin/movies at position 8 of 11 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
08:29:48,124 DEBUG qtp1624348237-15 AnonymousAuthenticationFilter:102 - Populated SecurityContextHolder with anonymous token: 'org.springframework.security.authentication.AnonymousAuthenticationToken@9055e4a6: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@957e: RemoteIpAddress: 127.0.0.1; SessionId: null; Granted Authorities: ROLE_ANONYMOUS'
08:29:48,125 DEBUG qtp1624348237-15 FilterChainProxy:337 - /admin/movies at position 9 of 11 in additional filter chain; firing Filter: 'SessionManagementFilter'
08:29:48,125 DEBUG qtp1624348237-15 SessionManagementFilter:92 - Requested session ID ncic677387xfiq2ciohmau1 is invalid.
08:29:48,126 DEBUG qtp1624348237-15 FilterChainProxy:337 - /admin/movies at position 10 of 11 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
08:29:48,126 DEBUG qtp1624348237-15 FilterChainProxy:337 - /admin/movies at position 11 of 11 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
08:29:48,126 DEBUG qtp1624348237-15 AntPathRequestMatcher:103 - Checking match of request : '/admin/movies'; against '/admin/*'
08:29:48,127 DEBUG qtp1624348237-15 FilterSecurityInterceptor:194 - Secure object: FilterInvocation: URL: /admin/movies; Attributes: [hasRole('ROLE_ADMIN') and hasIpAddress('127.0.0.1') and over18]
08:29:48,127 DEBUG qtp1624348237-15 FilterSecurityInterceptor:310 - Previously Authenticated: org.springframework.security.authentication.AnonymousAuthenticationToken@9055e4a6: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@957e: RemoteIpAddress: 127.0.0.1; SessionId: null; Granted Authorities: ROLE_ANONYMOUS
08:29:48,129 DEBUG qtp1624348237-15 CustomWebSecurityExpressionRoot:22 - CustomWebSecurityExpressionRoot()- call
08:29:48,154 DEBUG qtp1624348237-15 AffirmativeBased:65 - Voter: org.springframework.security.web.access.expression.WebExpressionVoter@35333295, returned: -1
08:29:48,157 DEBUG qtp1624348237-15 ExceptionTranslationFilter:165 - Access is denied(user is anonymous); redirecting to authentication entry point
org.springframework.security.access.AccessDeniedException: Access is denied at org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:83)
at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:206)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:115)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:84)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:113)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:103)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:113)
...
在初始化时,您可以看到用户正确地在日志中输入用户HashMap:
08:29:25,912 DEBUG main CustomInMemoryUserDetailsManager:26 - CustomInMemoryUserDetailsManager()- put username: admin last name: Scarioni authority: [ROLE_ADMIN]
我注意到用户是匿名进来的,我不知道为什么。任何帮助将不胜感激。
由于 麦克