Spring Security始终使用自定义JdbcDaoImpl进行身份验证

时间:2014-05-15 16:12:10

标签: java spring spring-security

我目前正在尝试使用基于Spring安全性的Webapp来将输入的用户名验证为多个数据库列。确切地说,我希望用户能够使用用户名或电子邮件或别名登录。因此我写了以下JdbcDaoImpl(电子邮件功能尚未实现,但它应该没有区别)

package de.dlr.gsoc.gssng.springSecurity;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.simple.ParameterizedRowMapper;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

public class CustomJDBCDaoImpl extends JdbcDaoImpl{



public CustomJDBCDaoImpl() {
    // TODO Auto-generated constructor stub
    super();
}

/* (non-Javadoc)
 * @see org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl#loadUserAuthorities(java.lang.String)
 */
@Override
protected List<GrantedAuthority> loadGroupAuthorities(String username) {
    String sql = "SELECT GroupAuthorities.Authority FROM Groups, GroupAuthorities, GroupMembers, Users WHERE (Users.Username = ? OR Users.Alias = ?) AND GroupMembers.Users_UserID = Users.UserID AND GroupMembers.Groups_GroupID = Groups.GroupID AND GroupAuthorities.Groups_GroupID = Groups.GroupID";



    JdbcTemplate template = new JdbcTemplate(getDataSource());

    CustomAuthority returnAuth = template.queryForObject(sql, new Object[] {username, username},  new AuthorityMapper());

    ArrayList<GrantedAuthority> returnList = new ArrayList<GrantedAuthority>();

    returnList.add(returnAuth);

    return returnList;
}

private class CustomAuthority implements GrantedAuthority
{
    /**
     * 
     */
    private static final long serialVersionUID = 6983133192699859170L;
    private String Authority;

    /* (non-Javadoc)
     * @see org.springframework.security.core.GrantedAuthority#getAuthority()
     */
    @Override
    public String getAuthority() {
        // TODO Auto-generated method stub
        return Authority;
    }

    public CustomAuthority(String _auth)
    {
        this.Authority = _auth;
    }
}

private class AuthorityMapper implements ParameterizedRowMapper<CustomAuthority> {

    @Override
    public CustomAuthority mapRow(ResultSet rs, int arg1) throws SQLException {
        return new CustomAuthority(rs.getString("Authority"));
    }

}

/* (non-Javadoc)
 * @see org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl#loadUsersByUsername(java.lang.String)
 */
@Override
public UserDetails loadUserByUsername(String username) {

    String sql = "SELECT Users.Username, Users.Password, Users.Enabled FROM Users WHERE Users.Username = ? OR Users.Alias = ?";


    JdbcTemplate template = new JdbcTemplate(getDataSource());

    User returnUser = template.queryForObject(sql, new UserMapper(), new Object[] {username, username});


    return returnUser;
}

private class UserMapper implements ParameterizedRowMapper<User> {

    @Override
    public User mapRow(ResultSet rs, int arg1) throws SQLException {
        return new User(rs.getString("Username"), rs.getString("Password"), rs.getBoolean("Enabled"), true, true, true, loadGroupAuthorities(rs.getString("Username")));
    }

}

}

它可以很好地从数据库加载userDetails。加载的密码也是正确的并且是加密形式的。但是,现在用户可以输入他喜欢的任何密码,并且将始终进行身份验证。如果我删除所有被覆盖的方法并返回到web.xml文件中的标准查询设置,一切都很完美。

我错过了什么吗?我是否还必须覆盖我的RememberMeAuthenticationProvider?

2 个答案:

答案 0 :(得分:0)

也许你可以做自己的customAuthenticationProvider:

Xml配置

<authentication-manager alias="authenticationManager">  
<authentication-provider ref="customAuthenticationProvider" />
</authentication-manager>

Java代码

@Component
public class CustomAuthenticationProvider implements AuthenticationProvider {

    private static final String CREDENCIALES_INCORRECTAS = "Username o password incorrectos";

    private static final String CUENTA_IS_NOT_ENABLED = "La cuenta de usuario no ha sido activada.";

    @Autowired
    private UsersService usersService;

    @Autowired
    private PasswordEncoderSha256 passwordEncoder;

    @Override
    public Authentication authenticate(Authentication authentication)
            throws AuthenticationException {
        String username = authentication.getName();
        String password = (String) authentication.getCredentials();

                //Find by username or email
        User user = usersService.findUserForAuthentication(username);

        if (user == null) {
            throw new BadCredentialsException(CREDENCIALES_INCORRECTAS);
        }

        if (!user.isEnabled()) {
            throw new BadCredentialsException(CUENTA_IS_NOT_ENABLED);
        }
        password = passwordEncoder.encodeSha256Password(password);

        if (!password.equals(user.getPassword())) {
            throw new BadCredentialsException(CREDENCIALES_INCORRECTAS);
        }

        Collection<? extends GrantedAuthority> authorities = user
                .getAuthorities();

        return new UsernamePasswordAuthenticationToken(user.getUsername(),
                password, authorities);
    }

    @Override
    public boolean supports(Class<?> arg0) {
        return true;
    }

}

答案 1 :(得分:0)

AbstractUserDetailsAuthenticationProvider.retrieveUser()从数据库加载UserDetails。然后,AbstractUserDetailsAuthenticationProvider.additionalAuthenticationChecks()检查密码是否匹配(在加密用户刚刚输入的密码之后)。它将呼叫委托给passwordEncoder.isPasswordValid()。因此,您必须确保您的密码编码器是什么。

如果您在此处粘贴beans.xml,则会更容易看到答案。