2012-12-23 14 views
11

मुझे आवश्यकता है कि प्रत्येक उपयोगकर्ता लॉग इन रहता है, जबकि उसका उपयोगकर्ता अपना उपयोगकर्ता नाम बदल सकता है। समस्या यह है कि स्प्रिंग सुरक्षा के प्रमाणीकरण टोकन में उपयोगकर्ता नाम (Principal) को अपडेट कैसे करें?वर्तमान उपयोगकर्ता के लिए स्प्रिंग सुरक्षा 3.1 के साथ लॉगिन नाम कैसे बदलें?

(क्योंकि मैं प्रमाणीकरण टोकन से प्रिंसिपल नेम का उपयोग कुछ व्यावसायिक उपयोग के मामलों में उपयोगकर्ता की पहचान करने मैं, इसे अद्यतन करने के लिए है।)

मैं उपयोग प्रपत्र आधारित और कुकी मुझे आधारित प्रवेश तो rememeber मेरी प्रमाणीकरण टोकन UsernamePaswordAuthenticationToken और RememberMeAuthenticationToken हैं। दोनों में एक क्षेत्र principal है जहां लॉगिन नाम संग्रहीत किया जाता है। दुर्भाग्य से यह चर final है, इसलिए मैं इसका मूल्य नहीं बदल सकता।

क्या किसी को पता है कि स्प्रिंग सिक्योरिटी प्रमाणीकरण टोकन में Principal को बदलने की सिफारिश कैसे करती है?

मेरे वर्तमान workarround कि मैं उपवर्गों एक अतिरिक्त नहीं अंतिम प्रिंसिपल क्षेत्र है और मूल एक के बजाय इस अतिरिक्त मुख्य वापस जाने के लिए getPrincipal() विधि ओवरराइड उस के साथ UsernamePaswordAuthenticationToken और RememberMeAuthenticationToken प्रतिस्थापित है। तब मैंने उन दो वर्गों को भी वर्गीकृत किया है जो इस टोकन को मूल के बजाए मेरे टोकन बनाने के लिए उत्पन्न करते हैं। --- लेकिन मुझे लगता है कि यह एक बड़ा हैक है।

उत्तर

6

टोकन i.e. 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 द्वारा मेरे मामले authenticationManager पाने के लिए पर काम करता है – Dickson

4

मैंने मार्सेल स्टोर द्वारा प्रस्तावित विचार लागू किया है।

टोकन यानी प्रमाणीकरण उप-वर्गों के साथ क्यों जाएं? Authentication.getPrincipal() आपके मामले में UserDetails का एक उदाहरण के लिए वापस नहीं करता है?

आप अपने खुद के UserDetails कार्यान्वयन (एक setUsername() विधि के साथ) की आपूर्ति की है, जबकि के सत्यापन आप घर के लिए स्वतंत्र हैं अगर मैं अपने मामले को सही ढंग से समझते हैं।

यह UserDetails परिवर्तनीय उपयोगकर्ता नाम के साथ आपत्ति है:

और मैं कार्यान्वयन को साझा करना चाहते। क्योंकि मैं इसे एक साथ उपयोग के साथ JDBC उपयोगकर्ता का विवरण सेवा है कि normaly इस कक्षाएं बना मैं इसे org.springframework.security.core.userdetails.User का एक उपवर्ग बनाया है।

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); 
    } 
} 

के लिए उपवर्ग मुझे आशा है कि किसी को भी इसका उपयोग कर सकते हैं।