shiro doGetAuthenticationInfo


 public SimpleAuthenticationInfo(Object principal, Object hashedCredentials, ByteSource credentialsSalt, String realmName) {         this.principals = new SimplePrincipalCollection(principal, realmName);         this.credentials = hashedCredentials;         this.credentialsSalt = credentialsSalt;     }

上面是SimpleAuthenticationInfo源碼的一個構造方法,這里第一個參數就是你剛才傳入的用戶名,第二個參數就是你傳入的密碼,但是 方法定義中這兩個參數都是Object類型,尤其是第一個principal參數,它的意義遠遠不止用戶名那么簡單,它是用戶的所有認證信息集合,登陸成 功后,<shiro:principal/>標簽一旦有property屬性,PrincipalTag類也就是標簽的支持類,會從 Subject的principalcollection里將principal取出,取出的就是你傳入的第一個參數,如果你傳了個string類型的用 戶名,那么你只能獲取用戶名。
仔細看那個this.principals=new SimplePrincipalCollection,這一行,這一行構造了一個新的對象並將引用給了principals,而principals就是principalcollection。

再來看Principal那個標簽<shiro:principal property=""/>那個,打開PrincipalTag類,看到onDoStartTag方法:

public int onDoStartTag() throws JspException {

        String strValue = null;         if (getSubject() != null) {             // Get the principal to print out             Object principal;             if (type == null) {                 principal = getSubject().getPrincipal();             } else {                 principal = getPrincipalFromClassName();             }             // Get the string value of the principal             if (principal != null) {                 if (property == null) {                     strValue = principal.toString();                 } else {                     strValue = getPrincipalProperty(principal, property);                 }             }         }         // Print out the principal value if not null         if (strValue != null) {             try {                 pageContext.getOut().write(strValue);             } catch (IOException e) {                 throw new JspTagException("Error writing [" + strValue + "] to JSP.", e);             }         }         return SKIP_BODY;     } 

看到那個Object principal這個方法變量了么?如果標簽里沒有type屬性,那么就直接調用getPrincipal方法,再打開這個方法,看到subject里是這么寫的:

    public Object getPrincipal() {

        return getPrimaryPrincipal(getPrincipals());

    } 
getPrincipals是獲取principalcollection,getprimaryprincipal就是獲取這個 principalcollection的第一個元素,用的是迭代器的方式獲取。具體的我不列出來了,請參見 SimplePrincipalcollection的源代碼。
第一個元素你最初放的是用戶名,所以你可以取得這個用戶名。 如果type不為空,就會去principalcollection中找和這個type類型一致的一個對象,看源碼:

   private Object getPrincipalFromClassName() {         Object principal = null;         try {             Class cls = Class.forName(type);             principal = getSubject().getPrincipals().oneByType(cls);         } catch (ClassNotFoundException e) {             if (log.isErrorEnabled()) {                 log.error("Unable to find class for name [" + type + "]");             }         }         return principal;     } 


那個oneByType方法就是在principalcollection中找和type屬性一致的那個類的對象,將其作為principal,如 果<shiro:property/>標簽有了property屬性,然后用java內省機制獲取bean的屬性,參見 getPrincipalProperty方法,因為方法體太長我就不列出了。 
所以你現在知道該怎么做了吧?
在你的realm里這么寫:

List<Object> principals=new ArrayList<Object>(); principals.add(user.getUsername()); principals.add(user); SimpleAuthenticationInfo info=new SimpleAuthenticationInfo( principals, user.getPassword(), ByteSource.Util.bytes(user.getCredentialsSalt()), this.getName());

構建一個list,第一個元素是用戶名,第二個元素是user對象。第一個元素用來登陸,第二個元素用來獲取登陸后user對象的屬性。
他們到底怎么判斷登陸的呢?
先參見HashedCredentialsMatcher類的這個方法,這是用來判斷是否可以登錄成功的方法:  

public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {         Object tokenHashedCredentials = hashProvidedCredentials(token, info);         Object accountCredentials = getCredentials(info);         return equals(tokenHashedCredentials, accountCredentials);     } 

其中第一個參數token就是controller里封裝的token,第二個參數info就是你剛才的 simpleauthenticationinfo,因為源碼層次比較深所以簡單點說,這個方法就是再判斷兩個密碼是否相等,因為兩個用戶名肯定是相等的 info的用戶名是token傳過來的,所以只對比密碼就可以了。 

  其中equals方法仍然是調用父類的方法,即一旦為ByteSource則進行byte匹配,否則進行引用匹配。只是這里的tokenHashedCredentials 和accountCredentials 和父類的方式不一樣,如下:

protected Object hashProvidedCredentials(AuthenticationToken token, AuthenticationInfo info) {
        Object salt = null;
        if (info instanceof SaltedAuthenticationInfo) {
            salt = ((SaltedAuthenticationInfo) info).getCredentialsSalt();
        } else {
            //retain 1.0 backwards compatibility:
            if (isHashSalted()) {
                salt = getSalt(token);
            }
        }
        return hashProvidedCredentials(token.getCredentials(), salt, getHashIterations());
    }
protected Hash hashProvidedCredentials(Object credentials, Object salt, int hashIterations) {
        String hashAlgorithmName = assertHashAlgorithmName();
        return new SimpleHash(hashAlgorithmName, credentials, salt, hashIterations);
    }

可以看到仍然是使用算法名稱和credentials(用戶提交的未加密的)、salt、hash次數構建一個SimpleHash(構造時進行加密)。
再看對於已加密的credentials則是也構建一個SimpleHash,但是不再進行加密過程:

protected Object getCredentials(AuthenticationInfo info) {
        Object credentials = info.getCredentials();

        byte[] storedBytes = toBytes(credentials);

        if (credentials instanceof String || credentials instanceof char[]) {
            //account.credentials were a char[] or String, so
            //we need to do text decoding first:
            if (isStoredCredentialsHexEncoded()) {
                storedBytes = Hex.decode(storedBytes);
            } else {
                storedBytes = Base64.decode(storedBytes);
            }
        }
        AbstractHash hash = newHashInstance();
        hash.setBytes(storedBytes);
        return hash;
    }
protected AbstractHash newHashInstance() {
        String hashAlgorithmName = assertHashAlgorithmName();
        return new SimpleHash(hashAlgorithmName);
    }

對於HashedCredentialsMatcher也就是說AuthenticationToken token, AuthenticationInfo info都去構建一個SimpleHash,前者構建時執行加密過程,后者(已加密)不需要去執行加密過程,然后匹配這兩個SimpleHash是否一致。然后就是HashedCredentialsMatcher的子類(全部被標記為已廢棄),如Md5CredentialsMatcher:

public class Md5CredentialsMatcher extends HashedCredentialsMatcher {

    public Md5CredentialsMatcher() {
        super();
        setHashAlgorithmName(Md5Hash.ALGORITHM_NAME);
    }
}
僅僅是將HashedCredentialsMatcher的算法改為md5,所以Md5CredentialsMatcher 本身就沒有存在的價值。HashedCredentialsMatcher其他子類都是同樣的道理。
至此CredentialsMatcher的三個分支都完成了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM