shiro 登录流程源码分析
-
获取subject
SecurityUtils.getSubject()
-
从ThreadContext获取subject
借助ThreadLocal实现线程私有
从线程私有变量的存储map中使用特定key(org.apache.shiro.util.ThreadContext_SUBJECT_KEY)获取subject对象
ThreadLocal#get()是从当前线程保存的私有map拷贝一个返回
-
-
-
如果subject为空则新构建一个
从公共subjectContext拷贝属性生成新subject的内置属性map
确保SecurityManager对象存在
确定关联的session
绑定principal
持久保存subject
绑定到某个线程
-
在web环境下拿到一个WebDelegatingSubject
-
获取用户提交的登录表单信息并生成一个Token,常用的
UsernamePasswordToken
-
执行login
currentUser.login(token);
-
清除runAs造成的身份信息
-
交给SecurityManager执行登录
-
首先认证token,如果成功构建一个subject实例代表认证过的账号身份
-
认证token交给
Authenticator
-
进入
AbstractAuthenticator
-
判断token不为null
-
调用抽象方法,做验证
protected abstract AuthenticationInfo doAuthenticate(AuthenticationToken token) throws AuthenticationException;
-
进入ModularRealmAuthenticator’
-
判断realms存在
-
由于单realm,进入
doSingleRealmAuthentication
-
委托给realm获取用户(存储在数据库中的)信息
-
realm先尝试从缓存中获取用户信息
-
获取不到则调用realm实现类的
doGetAuthenticationInfo
方法 -
获取到信息后委托给matcher进行信息匹配(页面传递的token与用户存储在后台数据库中的信息对比) matcher也可重写在配置securityManager时注入
/** * Shiro Realm 免密登录 */ @Bean public NoPassRealm noPassRealm(MyHashedCredentialsMatcher matcher) { NoPassRealm noPassRealm = new NoPassRealm(); noPassRealm.setCredentialsMatcher(matcher); return noPassRealm; }
-
若通过realm获取信息成功并通过matcher匹配成功
-
-
在authenticator中通知AuthenticationListener认证成功
此处是用于扩展,暂无实现
-
-
-
-
SecurityManager 构建登录成功后的subject
-
判断是否要实现记住我功能
-
-
-
若token是HostAuthenticationToken 则从中获取host
-
从验证成功的subject中获取session并装饰,会话绑定subject
-
subject与session互相依赖
-
-
shiro在服务器重启后如何获取当前登录用户
多重委托
-
subject -> securityManager
-
securityManager->authenticator
-
authoenticator中含有realm
小结
shiro登录流程图
额外知识
-
InheritableThreadLocal 子线程默认拥有父线程所有参数
-
authenticator中内置认证机制,认证机制默认为一个realm校验成功就成功,策略模式
-
监听者设计模式用于登录验证成功时的扩展
-
装饰模式用于session的转换