Shiro的login认证原理源码分析

刚才在整Shiro的时候,发现登录密码一直说不对,然后debug看了一下源码。最终发现 shiro 的 md5 多次加密和我的多次 md5 加密结果不太一样,然后索性直接用它的,最终解决。


  1. public static String toMd5(String pwd, String salt, int i) {
  2.         Md5Hash toMd5 = new Md5Hash(pwd, salt, i);
  3.         return toMd5.toString();
  4.     }

  

但是这个过程,看了一下登录认证的源码,这里记录一下。   

1.通过 subject.login(token) 触发登录过程


  1. Subject subject = SecurityUtils.getSubject();
  2. UsernamePasswordToken token = new UsernamePasswordToken(user.getUserName(), loginPwd);
  3. subject.login(token);


  2.Subject的登录将委托给SecurityManager,SecurityManager的login方法实际上是产生了一个新的Subject,然后将相关属性赋予当前调用者Subject:  


 3.点击左侧的箭头,查看实现发现 DefaultSecurityManager实现了login方法:    

4.父类AuthenticatingSecurityManager实现authenticate方法:  

  5.先看上面那个,无参构造器,给 authenticator 认证器初始化为 ModularRealmAuthenticator 对象。 我们看看 ModularRealmAuthenticator 这个类 默认无参构造器,指定策略(如果是多Realm有三种策略:

①至少成功一个就行 

②全部成功才行 

③必须第一个成功才行)为至少一个成功就行    

查看里面的授权方法,返回最终授权信息,就在这里  

这个地方我们待会儿看 因为我们要回到刚才4那里调用 authenticator.authenticate() 方法  


 6.authenticate() 方法 ModularRealmAuthenticator 类没有,但是它的父类 AbstractAuthenticator 有 我们来看 AbstractAuthenticator 类,找到 authenticate() 方法    

发现里面调用了 doAuthenticate() 方法,这是个抽象方法,这所以是抽象方法,就是为了让继承它的子类自己去实现它。  

7.AbstractAuthenticator类只有一个子类,就是之前那个 ModularRealmAuthenticator 类,里面有 doAuthenticate() 方法 没错,就是这个图    

我们目前是单 Realm 模式,那我们直接看 doSingleRealmAuthentication() 方法  

这里调用了 Realm 接口中的 getAuthenticationInfo() 方法 我们去看它的实现   8.Realm 接口唯一实现类 AuthenticatingRealm,这也是一个抽象类,因为里面的有一个 doGetAuthenticationInfo() 方法是抽象方法 我们先看 getAuthenticationInfo() 方法实现  

这里先获得这个 info,然后进行 info 和 token 比较是否相等 info 是从数据库查询出来的密码信息(比如加密后的 a021a665f503979c06f50b8de66a4218); 而token是用户登录时输入的密码(目前还没加密,可能还是 123456)   


9.我们先说这个获得 info 授权信息,先从缓存里拿,缓存里没有就执行 doGetAuthenticationInfo() 方法拿。

 我们还记得 doGetAuthenticationInfo() 是一个抽象方法,谁实现了它呢? 有这几个类,包括我们自己写的 MyShiroRealm ,总共5个实现类    

因为我们的 Shiro 配置文件已经设置了采用 MyShiroRealm 的实例  

 所以会去找 MyShiroRealm 中的 doGetAuthenticationInfo() 方法  

如果这里执行到第49行,返回 null,就会直接认证失败,报用户不存在异常 如果最后执行到了57行,返回认证信息,里面有用户的数据库密码,将会为下面准备使用。   


10.我们回到第8步中图片的 assertCredentialsMatch(token, info); 简单来说,就是判断用户输入的密码和数据库中查询出来的密码是否相等    

doCredentialsMatch() 是接口 CredentialsMatcher 中的方法,这个方法有四个实现类中有  

  怎么知道,去找哪个实现类呢? 也是在 ShiroConfig 中设置的,可以知道是 HashedCredentialsMatcher    

11.HashedCredentialsMatcher 中的 doCredentialsMatch() 方法实现    

先获得 token 中的密码,需要根据第10步图中配置的加密方法和次数进行加密,最终得到如 a021a665f503979c06f50b8de66a4218 info 中的密码可以直接从对象里获取,无需加密 然后调用重写的 equals 方法比较两个字符串实现相等。 如果是 true,第8步里那个断言就不会抛异常,就会正常往下执行,返回 info   12.我们回到第3步中的DefaultSecurityManager类调用 login 方法  

目前已经认证成功了,用户名和密码是正确的。

 现在就需要创建 Subject,里面主要是创建 Session,设置 Principal(用户对象),将 subject 持久化存起来。 后面的就不介绍了

发表评论

目前评论:1

  • avatar HickSalmon

    11111