2012-12-23 25 views
11

我有要求,每個用戶可以更改自己的用戶名,而他仍然登錄。問題是如何更新Spring Security的身份驗證令牌用戶名(Principal)?如何使用Spring Security 3.1更改當前用戶的登錄名?

我必須更新它,因爲我用的是主體名稱由身份驗證令牌標識用戶在某些業務用例。

我使用基於表單和cookie的rememeber我基於登錄,這樣我身份驗證令牌是UsernamePaswordAuthenticationTokenRememberMeAuthenticationToken。兩者都有一個principal的字段,其中存儲了登錄名。不幸的是,這個變量是final,所以我無法改變它的價值。

有沒有人知道Spring Security推薦如何更改認證令牌中的Principal

我現在workarround是,我更換了UsernamePaswordAuthenticationTokenRememberMeAuthenticationToken與具有額外的不是最終的主要領域和覆蓋getPrincipal()方法,而不是回到原來的這種額外的主要子類。然後,我還創建了兩個類,這兩個類產生這個標記來創建我的標記,而不是原來的標記。 ---但我覺得這是一個很大的破解。

回答

6

爲什麼要用代幣Authentication的子類? Authentication.getPrincipal()在您的情況下是否返回UserDetails的實例?

如果你提供你自己的UserDetails實現(一用一setUsername()方法),同時驗證你家免費的,如果我理解正確你的情況。

+0

我已經實現你的想法,它的工作。 http://stackoverflow.com/a/14174404/280244 – Ralph

7

我做過類似的東西,這是一個黑客位,但我所做的更改並保存新的UserDetails,然後添加一個新的一個新的認證令牌的會話更新的憑據:

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

它工作在我的情況通過@Autowired AuthenticationManager獲取身份驗證管理器 – Dickson

4

我已經實現了由Marcel STOR提出的想法。

爲什麼要使用令牌即身份驗證子類?在你的情況下,Authentication.getPrincipal()不會返回UserDetails的一個實例嗎?

如果你提供你自己的UserDetails實現(一用一setUsername()方法),同時驗證你家免費的,如果我理解正確你的情況。

我想分享的實現:

這是的UserDetails與修改用戶名反對。我將它作爲org.springframework.security.core.userdetails.User的一個子類,因爲我將它與Jdbc用戶詳細信息服務一起使用,該服務正常創建此類。

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 <code>User</code> with the details required by 
    * {@link org.springframework.security.authentication.dao.DaoAuthenticationProvider}. 
    * 
    * @param username the username presented to the 
    *  <code>DaoAuthenticationProvider</code> 
    * @param password the password that should be presented to the 
    *  <code>DaoAuthenticationProvider</code> 
    * @param enabled set to <code>true</code> if the user is enabled 
    * @param accountNonExpired set to <code>true</code> if the account has not 
    *  expired 
    * @param credentialsNonExpired set to <code>true</code> if the credentials 
    *  have not expired 
    * @param accountNonLocked set to <code>true</code> 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 <code>null</code> value was passed 
    *   either as a parameter or as an element in the 
    *   <code>GrantedAuthority</code> collection 
    */ 
    public UpdateableUserDetails(final String username, final String password, final boolean enabled, 
      final boolean accountNonExpired, final boolean credentialsNonExpired, final boolean accountNonLocked, 
      final Collection<? extends GrantedAuthority> 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 
    *  <code>DaoAuthenticationProvider</code> 
    * @param password the password that should be presented to the 
    *  <code>DaoAuthenticationProvider</code> 
     * @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<? extends GrantedAuthority> 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. 
    * <p> 
    * 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 <tt>loadUserByUsername</tt> 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<GrantedAuthority> combinedAuthorities) { 
     String returnUsername = userFromUserQuery.getUsername(); 

     if (!isUsernameBasedPrimaryKey()) { 
      returnUsername = username; 
     } 

     return new UpdateableUserDetails(returnUsername, 
       userFromUserQuery.getPassword(), 
       userFromUserQuery.isEnabled(), 
       true, 
       true, 
       true, 
       combinedAuthorities); 
    } 
} 

我希望有人能使用它。

相關問題