我目前正在尝试使用基于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?
答案 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,则会更容易看到答案。