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的三个分支都完成了。

转载于:https://www.cnblogs.com/albert-think/p/6046115.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值