流程解析
首先调用login方法进行身份认证 根据applicationContext.xml的配置文件去查询认证器ModularRealmAuthenticator 去ModularRealmAuthenticator中执行认证方法doAuthenticate 首先判断是单realm的验证还是多realm的验证(此处配置了多realm) 则执行doMultiRealmAuthentication(如果是单realm的话执行doSingleRealmAuthentication) 首先加载认证认证策略(此处我们配置了AtLeastOneSuccessfulStrategy) 然后开始for循环所有的realm,此处首先验证supportToken(我们自定义的realms里面实现的三个方法) [重点]getAuthenticationInfo(token)获得我们从数据库中加载的用户信息,这里我们会传入token参数 也就是前台界面传进来的用户名密码(token),此时拿到了前台的以及数据库的用户信息,然后开始进行密码比较 1 function doMultiRealmAuthentication 2 for (Realm realm : realms) { 3 aggregate = strategy.beforeAttempt(realm, token, aggregate); 4 if (realm.supports(token)) { 5 AuthenticationInfo info = realm.getAuthenticationInfo(token); 6 } 7 } 其中第5行进行了密码比对 HashedCredentialsMatcher doCredentialsMatch(token,info) 过程:realm.getAuthenticationInfo(token);(此过程涉及缓存cache) AuthenticatingRealm.getAuthenticationInfo(token) 首先从缓存中查询此token对应的account信息 如果查到直接启用,否则执行自定义的info = doGetAuthenticationInfo(token); 从数据库中取得account信息 然后缓存查到的token和account信息 然后执行assertCredentialsMatch(token, info); 其中开始先创建CredentialsMatcher密码匹配器,doCredentialsMatch(token, info); 执行HashedCredentialsMatcher.doCredentialsMatch开始密码比对
其他重点注释:
shiro url匹配模式: ?:匹配一个字符,如:/admin1,但是不能匹配/admin,/admin/ * :匹配0个或者多个字符,如:/admin,/admin123,但是不能匹配admin/a **:匹配多重路径,如:/admin,admin/a/b shiro用户认证流程 1. 获取当前的 Subject. 调用 SecurityUtils.getSubject(); 2. 测试当前的用户是否已经被认证. 即是否已经登录. 调用 Subject 的 isAuthenticated() 3. 若没有被认证, 则把用户名和密码封装为 UsernamePasswordToken 对象 1). 创建一个表单页面 2). 把请求提交到 SpringMVC 的 Handler(上面三步都是在handler里面完成的) 3). 获取用户名和密码. 4. 执行登录: 调用 Subject 的 login(AuthenticationToken) 方法. 5. 自定义 Realm 的方法, 从数据库中获取对应的记录, 返回给 Shiro. 1). 实际上需要继承 org.apache.shiro.realm.AuthenticatingRealm 类 2). 实现 doGetAuthenticationInfo(AuthenticationToken) 方法. 6. 由 shiro 完成对密码的比对. 密码的比对: 通过 AuthenticatingRealm 的 credentialsMatcher 属性来进行的密码的比对! 1. 如何把一个字符串加密为 MD5 2. 替换当前 Realm 的 credentialsMatcher 属性. 直接使用 HashedCredentialsMatcher 对象, 并设置加密算法即可. 1. 授权需要继承 AuthorizingRealm 类, 并实现其 doGetAuthorizationInfo 方法 2. AuthorizingRealm 类继承自 AuthenticatingRealm, 但没有实现 AuthenticatingRealm 中的 doGetAuthenticationInfo, 所以认证和授权只需要继承 AuthorizingRealm 就可以了. 同时实现他的两个抽象方法. 1. 为什么使用 MD5 盐值加密: 2. 如何做到: 1). 在 doGetAuthenticationInfo 方法返回值创建 SimpleAuthenticationInfo 对象的时候, 需要使用 SimpleAuthenticationInfo(principal, credentials, credentialsSalt, realmName) 构造器 2). 使用 ByteSource.Util.bytes() 来计算盐值. 3). 盐值需要唯一: 一般使用随机字符串或 user id 4). 使用 new SimpleHash(hashAlgorithmName, credentials, salt, hashIterations); 来计算盐值加密后的密码的值.