春季安全; custom-filter和user-service-ref不能一起工作

时间:2013-03-11 21:58:26

标签: login spring-security spring-3 spring-security-ldap

我正在尝试使用自定义过滤器实现Spring安全授权。

security.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<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" 
   xmlns:p="http://www.springframework.org/schema/p" 
   xmlns:util="http://www.springframework.org/schema/util"
   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
        http://www.springframework.org/schema/util 
        http://www.springframework.org/schema/util/spring-util-3.1.xsd">

    <http pattern="/resources" security="none" />

    <http auto-config="false" use-expressions="true" entry-point- ref="authenticationEntryPoint">
        <custom-filter position="BASIC_AUTH_FILTER" ref="loginFilter"/>
        <intercept-url pattern="/login" access="permitAll" />
        <intercept-url pattern="/favicon.ico" access="permitAll"/>
    </http>

    <beans:bean id="authenticationEntryPoint" class="com.my.org.MyAuthenticationEntryPoint"/>


    <beans:bean id="loginFilter"
      class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter">
        <beans:property name="authenticationManager" ref="authenticationManager"/>
        <beans:property name="filterProcessesUrl" value="/j_spring_security_check"/>
        <beans:property name="authenticationSuccessHandler"  >
            <beans:bean class="com.my.org.MyAuthenticationSuccessHandler"/>
    </beans:property>
        <beans:property name="authenticationFailureHandler">
            <beans:bean class="com.my.org.MyAuthenticationFailureHandler"/>
        </beans:property>
    </beans:bean>

    <authentication-manager alias="authenticationManager">
            <authentication-provider user-service-ref="customUserDetailsService">
                    <password-encoder hash="sha"/>
            </authentication-provider>
    </authentication-manager>

</beans:beans>

CustomUserDetailsS​​ervice

/**
 * A custom {@link UserDetailsService} where user information
 * is retrieved from a JPA repository
 */
@Service
@Transactional(readOnly = true)
public class CustomUserDetailsService implements UserDetailsService {

private static final Logger logger = LoggerFactory.getLogger(CustomUserDetailsService.class);

@Autowired
private UserRepository userRepository;

/**
 * Returns a populated {@link UserDetails} object. 
 * The username is first retrieved from the database and then mapped to 
 * a {@link UserDetails} object.
 */
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
    try {

        logger.info("username-1-->"+username);
        com.cbr.model.User domainUser = userRepository.findByUsername(username);
        logger.info("domainUser-1-->"+domainUser.getPassword());
        logger.info("role-1-->"+domainUser.getRole().getRole());

        boolean enabled = true;
        boolean accountNonExpired = true;
        boolean credentialsNonExpired = true;
        boolean accountNonLocked = true;

        return new User(
                domainUser.getUsername(), 
                domainUser.getPassword().toLowerCase(),
                enabled,
                accountNonExpired,
                credentialsNonExpired,
                accountNonLocked,
                getAuthorities(domainUser.getRole().getRole()));

    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

/**
 * Retrieves a collection of {@link GrantedAuthority} based on a numerical role
 * @param role the numerical role
 * @return a collection of {@link GrantedAuthority
 */
public Collection<? extends GrantedAuthority> getAuthorities(Integer role) {
    List<GrantedAuthority> authList = getGrantedAuthorities(getRoles(role));
    return authList;
}

/**
 * Converts a numerical role to an equivalent list of roles
 * @param role the numerical role
 * @return list of roles as as a list of {@link String}
 */
public List<String> getRoles(Integer role) {
    List<String> roles = new ArrayList<String>();

    if (role.intValue() == 1) {
        roles.add("ROLE_USER");
        roles.add("ROLE_ADMIN");

    } else if (role.intValue() == 2) {
        roles.add("ROLE_USER");
    }

    return roles;
}

/**
 * Wraps {@link String} roles to {@link SimpleGrantedAuthority} objects
 * @param roles {@link String} of roles
 * @return list of granted authorities
 */
public static List<GrantedAuthority> getGrantedAuthorities(List<String> roles) {
    List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
    for (String role : roles) {
        authorities.add(new SimpleGrantedAuthority(role));
    }
    return authorities;
}

}

MyAuthenticationEntryPoint

public class MyAuthenticationEntryPoint implements AuthenticationEntryPoint {

    private Log log = LogFactory.getLog(MyAuthenticationEntryPoint.class);

    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {

        log.info("point-1");

        response.sendError(HttpServletResponse.SC_FORBIDDEN);
    }
}

MyAuthenticationSuccessHandler

public class MyAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {

    private Log log = LogFactory.getLog(MyAuthenticationSuccessHandler.class);

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,Authentication authentication) throws IOException, ServletException {
        // This is actually not an error, but an OK message. It is sent to avoid redirects.
        log.info("point-2");
        response.sendError(HttpServletResponse.SC_OK);
    }
}

MyAuthenticationFailureHandler

public class MyAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler {

    private Log log = LogFactory.getLog(MyAuthenticationFailureHandler.class);

    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,AuthenticationException exception) throws IOException, ServletException {
        log.info("point-3");
        response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Authentication Failed: " + exception.getMessage());
    }
}

当我尝试登录时,它会进入CustomUserDetailsS​​ervice并成功从数据库中检索用户详细信息。

但它总是访问authenticationFailureHandler,无论凭据是否正确。 (INFO : com.my.org.MyAuthenticationFailureHandler - point-3

有人可以帮我这个吗?感谢

1 个答案:

答案 0 :(得分:3)

您将身份验证提供程序配置为使用sha密码编码(<password-encoder hash="sha"/>),这意味着它将对传入登录请求中显示的密码进行sha-encode,并将该编码值与密码进行比较存储在UserDetails对象中(因此预期也会进行sha编码)。在UserDetails中创建CustomUserDetailsService.loadUserByUsername()对象时,将从存储库加载用户,并使用toLowerCase()转换其密码。现在,你为什么要那样做?该值应该是sha编码的密码。通过转换密码的哈希,您可以保证用户无法使用其原始密码登录。 但即使您以纯文本形式存储密码(在这种情况下应删除password-encoder配置),为什么要在UserDetails中将其设为小写?如果你这样做,并且用户将他的密码设置为“秘密”,他以后只能用“秘密”进行身份验证。