希望我的最后一个问题。到目前为止,我已经实现了我自己的自定义 UserDetails 和 UserDetailsService 类,以便我可以传递在创建密码时使用的随机盐。密码的哈希是 SHA512。但是,在尝试登录时,我总是得到用户/密码组合不正确,我似乎无法弄清楚原因。
我将哈希和盐作为 blob 存储在数据库中,关于问题所在的任何想法?
Security-applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans
xmlns:sec="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.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.0.xsd">
<sec:http auto-config='true' access-denied-page="/access-denied.html">
<!-- NO RESTRICTIONS -->
<sec:intercept-url pattern="/login.html" access="IS_AUTHENTICATED_ANONYMOUSLY" />
<sec:intercept-url pattern="/*.html" access="IS_AUTHENTICATED_ANONYMOUSLY" />
<!-- RESTRICTED PAGES -->
<sec:intercept-url pattern="/admin/*.html" access="ROLE_ADMIN" />
<sec:intercept-url pattern="/athlete/*.html" access="ROLE_ADMIN, ROLE_STAFF" />
<sec:form-login login-page="/login.html"
login-processing-url="/loginProcess"
authentication-failure-url="/login.html?login_error=1"
default-target-url="/member" />
<sec:logout logout-success-url="/login.html"/>
</sec:http>
<beans:bean id="customUserDetailsService" class="PATH.TO.CustomUserDetailsService"/>
<beans:bean id="passwordEncoder" class="org.springframework.security.authentication.encoding.ShaPasswordEncoder">
<beans:constructor-arg value="512"/>
</beans:bean>
<sec:authentication-manager>
<sec:authentication-provider user-service-ref="customUserDetailsService">
<sec:password-encoder ref="passwordEncoder">
<sec:salt-source user-property="salt"/>
</sec:password-encoder>
</sec:authentication-provider>
</sec:authentication-manager>
</beans:beans>
CustomUserDetails.java
public class CustomUserDetails implements UserDetails {
private int userID;
private String username;
private String password;
private Collection<GrantedAuthority> authorities;
private boolean accountNonExpired;
private boolean accountNonLocked;
private boolean credentialsNonExpired;
private boolean enabled;
private String salt;
public CustomUserDetails() {
}
public CustomUserDetails(int userID, Collection<GrantedAuthority> authorities, String username, String password, boolean accountNonExpired, boolean accountNonLocked, boolean credentialsNonExpired, boolean enabled, String salt) {
this.userID = userID;
this.authorities = authorities;
this.username = username;
this.password = password;
this.accountNonExpired = accountNonExpired;
this.accountNonLocked = accountNonLocked;
this.credentialsNonExpired = credentialsNonExpired;
this.enabled = enabled;
this.salt = salt;
}
@Override
public Collection<GrantedAuthority> getAuthorities() {
return authorities;
}
public int getUserID() {
return userID;
}
public void setUserID(int userID) {
this.userID = userID;
}
@Override
public String getPassword() {
return password;
}
@Override
public String getUsername() {
return username;
}
@Override
public boolean isAccountNonExpired() {
return accountNonExpired;
}
@Override
public boolean isAccountNonLocked() {
return accountNonLocked;
}
@Override
public boolean isCredentialsNonExpired() {
return credentialsNonExpired;
}
@Override
public boolean isEnabled() {
return enabled;
}
public String getSalt() {
return salt;
}
public void setAccountNonExpired(boolean accountNonExpired) {
this.accountNonExpired = accountNonExpired;
}
public void setAccountNonLocked(boolean accountNonLocked) {
this.accountNonLocked = accountNonLocked;
}
public void setAuthorities(Collection<GrantedAuthority> authorities) {
this.authorities = authorities;
}
public void setCredentialsNonExpired(boolean credentialsNonExpired) {
this.credentialsNonExpired = credentialsNonExpired;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public void setPassword(String password) {
this.password = password;
}
public void setUsername(String username) {
this.username = username;
}
public void setSalt(String salt) {
this.salt = salt;
}
}
CustomUserDetailsService.java
public class CustomUserDetailsService implements UserDetailsService {
private User_dao userDao;
@Autowired
public void setUserDao(User_dao userDao) {
this.userDao = userDao;
}
@Override
public CustomUserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException {
MyUser myUser = new MyUser();
myUser.setUsername(username);
try {
userDao.getUserByUsername(myUser);
} catch (Throwable e) {
}
if (myUser == null) {
throw new UsernameNotFoundException("Username not found", username);
} else {
List<GrantedAuthority> authList = new ArrayList<GrantedAuthority>();
authList.add(new GrantedAuthorityImpl(myUser.getUserRole().getAuthority()));
int userID = myUser.getUserID();
boolean accountNonExpired = true;
boolean accountNonLocked = myUser.isNonLocked();
boolean credentialsNonExpired = true;
boolean enabled = myUser.isEnabled();
String password = "";
String salt = "";
password = new String(myUser.getHash);
salt = new String(myUser.getSalt());
CustomUserDetails user = new CustomUserDetails(userID, authList, username, password, accountNonExpired, accountNonLocked, credentialsNonExpired, enabled, salt);
return user;
}
}
}
密码创建
public byte[] generateSalt() throws NoSuchAlgorithmException {
SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
byte[] salt = new byte[20];
random.nextBytes(salt);
return salt;
}
public byte[] generateHash(byte[] salt, String pass) throws NoSuchAlgorithmException {
MessageDigest digest = MessageDigest.getInstance("SHA-512");
digest.update(salt);
byte[] hash = digest.digest(pass.getBytes());
return hash;
}
调用方法:
byte[] salt = generateSalt();
byte[] hash = generateHash(salt, password);
Which I then store in the db.