如何使用Spring Security 3.1更改当前用户的登录名?

我要求每个用户在登录时都可以更改自己的用户名。问题是如何在Spring Security的身份validation令牌中更新用户名( Principal )?

我必须更新它,因为我使用身份validation令牌中的原始名称来识别某些业务用例中的用户。

我使用基于表单和cookie记忆我的登录,所以我的身份validation令牌是UsernamePaswordAuthenticationTokenRememberMeAuthenticationToken 。 两者都有一个存储登录名的字段principal 。 不幸的是这个变量是final ,所以我不能改变它的价值。

有没有人知道Spring Security如何推荐更改身份validation令牌中的Principal

我当前的工作原理是我将UsernamePaswordAuthenticationTokenRememberMeAuthenticationToken替换为具有附加非最终主要字段的子类,并覆盖getPrincipal()方法以返回此附加主体而不是原始主体。 然后我还将生成此标记的两个类子类化,以创建我的标记而不是原始标记。 —但我觉得这是一个很大的黑客。

为什么选择令牌Authentication子类? Authentication.getPrincipal()是否在您的情况下返回UserDetails的实例?

如果你提供了自己的UserDetails实现(一个带有setUsername()方法),那么如果我正确理解你的情况,那么在你认证你是免费的。

我做了类似的事情,这有点像黑客,但我所做的是更改并保存新的UserDetails,然后为会话添加一个新的身份validation令牌以获取更新的凭据:

 Authentication request = new UsernamePasswordAuthenticationToken(user.getUsername(), password); Authentication result = authenticationManager.authenticate(request); SecurityContextHolder.getContext().setAuthentication(result); 

我实施了MarcelStör提出的想法。

为什么选择令牌即认证子类? Authentication.getPrincipal()是否在您的情况下返回UserDetails的实例?

如果你提供了自己的UserDetails实现(一个带有setUsername()方法),那么如果我正确理解你的情况,那么在你认证你是免费的。

我想分享实施:

这是具有可修改用户名的UserDetails对象。 我使它成为org.springframework.security.core.userdetails.User的子类,因为我将它与Jdbc User Details Service一起使用,它正常地创建了这个类。

 import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.userdetails.User; /** * Extension of {@link User} where it is possible to change the username. */ public class UpdateableUserDetails extends User { /** The Constant serialVersionUID. */ private static final long serialVersionUID = 9034840503529809003L; /** * The user name that can be modified. * It "overrides" the username field from class {@link User}. */ private String modfiableUsername; /** * Construct the User with the details required by * {@link org.springframework.security.authentication.dao.DaoAuthenticationProvider}. * * @param username the username presented to the * DaoAuthenticationProvider * @param password the password that should be presented to the * DaoAuthenticationProvider * @param enabled set to true if the user is enabled * @param accountNonExpired set to true if the account has not * expired * @param credentialsNonExpired set to true if the credentials * have not expired * @param accountNonLocked set to true if the account is not * locked * @param authorities the authorities that should be granted to the caller * if they presented the correct username and password and the user * is enabled. Not null. * * @throws IllegalArgumentException if a null value was passed * either as a parameter or as an element in the * GrantedAuthority collection */ public UpdateableUserDetails(final String username, final String password, final boolean enabled, final boolean accountNonExpired, final boolean credentialsNonExpired, final boolean accountNonLocked, final Collection authorities) throws IllegalArgumentException { super(username, password, enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, authorities); this.modfiableUsername = username; } /** * Calls the more complex constructor with all boolean arguments set to {@code true}. * @param username the username presented to the * DaoAuthenticationProvider * @param password the password that should be presented to the * DaoAuthenticationProvider * @param authorities the authorities that should be granted to the caller * if they presented the correct username and password and the user * is enabled. Not null. */ public UpdateableUserDetails(final String username, final String password, final Collection authorities) { super(username, password, authorities); this.modfiableUsername = username; } /** * Return the modifiable username instead of the fixed one. * * @return the username */ @Override public String getUsername() { return this.modfiableUsername; } public void setUsername(final String username) { this.modfiableUsername = username; } /** * Returns {@code true} if the supplied object is a {@code User} instance with the * same {@code username} value. * 

* In other words, the objects are equal if they have the same user name, representing the * same principal. * * @param rhs the other object * @return true if equals */ @Override public boolean equals(final Object rhs) { if (rhs instanceof User) { return this.modfiableUsername.equals(((User) rhs).getUsername()); } return false; } /** * Returns the hashcode. * * In order not to get any problems with any hash sets that based on the fact that this hash is not changed * over livetime and not to fail one of the constraints for {@link Object#hashCode()}, * this method always returns the same constant hash value. * * I expect that this is no such deal, because we expect not to have so many logged in users, so the hash sets * that use this as an key will not get so slow. * * @return the hash */ @Override public int hashCode() { return 1; } /** * Like {@link User#toString()}, but print the modifiable user name. * * @return the string representation with all details */ @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append(super.toString()).append(": "); sb.append("Username: ").append(this.modfiableUsername).append("; "); sb.append("Password: [PROTECTED]; "); sb.append("Enabled: ").append(isEnabled()).append("; "); sb.append("AccountNonExpired: ").append(isAccountNonExpired()).append("; "); sb.append("credentialsNonExpired: ").append(isCredentialsNonExpired()).append("; "); sb.append("AccountNonLocked: ").append(isAccountNonLocked()).append("; "); if (!getAuthorities().isEmpty()) { sb.append("Granted Authorities: "); boolean first = true; for (GrantedAuthority auth : getAuthorities()) { if (!first) { sb.append(","); } first = false; sb.append(auth); } } else { sb.append("Not granted any authorities"); } return sb.toString(); } }

UserDetailsService的子类

 import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl; /** * Create {@link UpdateableUserDetails} instead of {@link org.springframework.security.core.userdetails.User} user details. */ public class JdbcDaoForUpdatableUsernames extends JdbcDaoImpl { /** * Instantiates a new jdbc dao for updatable usernames impl. * * @param privilegesService the privileges service */ public JdbcDaoForUpdatableUsernames(final PrivilegesService privilegesService) { super(privilegesService); } /** * Can be overridden to customize the creation of the final UserDetailsObject which is * returned by the loadUserByUsername method. * * @param username the name originally passed to loadUserByUsername * @param userFromUserQuery the object returned from the execution of the * @param combinedAuthorities the combined array of authorities from all the authority loading queries. * @return the final UserDetails which should be used in the system. */ @Override protected UserDetails createUserDetails(final String username, final UserDetails userFromUserQuery, final List combinedAuthorities) { String returnUsername = userFromUserQuery.getUsername(); if (!isUsernameBasedPrimaryKey()) { returnUsername = username; } return new UpdateableUserDetails(returnUsername, userFromUserQuery.getPassword(), userFromUserQuery.isEnabled(), true, true, true, combinedAuthorities); } } 

我希望有人也可以使用它。