基本描述以及shiro是如何执行的,包含认证和授权流程
基本描述
- Apache Shiro是Java的一个安全(权限)框架
- 可以在JavaSE,javaEE环境
- 功能点:认证,授权,加密、会话管理、web集成、缓存等

应用程序角度

Shiro内部架构

例子
1 | public class UserRealm extends AuthorizingRealm { |
工作流程
入口:DelegatingFilterProxy
web.xml中的shiro入口
1 | <filter> |
DelegatingFilterProxy 是Filter的代理,代理的是spring容器中的filter-name一样的bean,
1 | <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> |
初始化:shiroFilter

ShiroFilterFactoryBean 实现了spring FactoryBean ,getObject获取实例
1 | public Object getObject() throws Exception { |
1 | protected AbstractShiroFilter createInstance() throws Exception { |
property filterChainDefinitions 属性,会调用setFilterChainDefinitions
1 | public void setFilterChainDefinitions(String definitions) { |
SecurityManager
FilterChainManager
1 | protected FilterChainManager createFilterChainManager() { |
DefaultFilterChainManager
1 | public DefaultFilterChainManager() { |
1 | protected void addDefaultFilters(boolean init) { |
DefaultFilter 过滤器
11个
1 | anon(AnonymousFilter.class), |
filterChains过滤器链
是一个linkedhashmap,key为配置的url,value为对应的过滤器
PathMatchingFilterChainResolver
创建了新的filterchainfilter,然后又被前面创建的覆盖了,有问题!!!
基于ant路径匹配方法匹配配置的url,
pathMatchingFilterChainResolver设置创建的FilterChainManager对象,所以URL匹配上后可以获取该URL需要应用的FilterChain了。
filter执行—匹配filter
(错误)通过请求的url,获取要走的过滤链,或者说,所有请求都走一样的过滤链,过滤器中由判断自己是否支持该请求
(正解),所有的请求走一个过滤器org.springframework.web.filter.DelegatingFilterProxy#doFilter
1 | org.apache.shiro.web.servlet.OncePerRequestFilter#doFilter==执行被代理类doFilter |
1 | protected void executeChain(ServletRequest request, ServletResponse response, FilterChain origChain){ |
1 | eg:FormAuthenticationFilter#doFilter===父类OncePerRequestFilter的doFilter |
1 | AdviceFilter#doFilterInternal |
filter 执行顺序
https://www.cnblogs.com/ljdblog/p/6237683.html
https://www.cnblogs.com/q95265/p/6928081.html
filter执行—doFilter
1 | public final void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain){ |
shiro通过一系列url匹配符配置URL应用上的Filter,然后在Filter中完成相应的任务。核心逻辑-doFilterInternal
OncePerRequestFilter:保证每个filter都执行一次
–AbstractShiroFilter
–AdviceFilter
AbstractShiroFilter
springfactorybean返回的bean核心就是这个类,封装为shirofilter
构造方法
1 | public void init() throws Exception { |
1 | protected void doFilterInternal(ServletRequest servletRequest, ServletResponse servletResponse, final FilterChain chain) { |
createSubject
每次调用都会创建subject
executeChain
1 | protected void executeChain(ServletRequest request, ServletResponse response, FilterChain origChain) { |
1 | protected FilterChain getExecutionChain(ServletRequest request, ServletResponse response, FilterChain origChain) { |
AdviceFilter
这个类很多方法实现了spring中的aop特点,prehandle前置通知,posthandle后置通知,异常不执行,afterCompletion (最终通知,一定会执行),可以根据需求覆写这几个方法
1 | public void doFilterInternal(ServletRequest request, ServletResponse response, FilterChain chain){ |
eg:
- preHandle
- 根据配置,访问URL:”/authenticated.jsp”时,会匹配上authc(FormAuthenticationFilter)
- FormAuthenticationFilter继承自PathMatchingFilter,所以返回true ,而logoutfilter会返回false,啥也没有返回给页面,页面显示空白
1 | protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception { |
1 | private boolean isFilterChainContinued(ServletRequest request, ServletResponse response, |
org.apache.shiro.web.filter.AccessControlFilter#onPreHandle
1 | public boolean onPreHandle(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception { |
isAccessAllowed:表示是否允许访问;mappedValue就是[urls]配置中拦截器参数部分,如果允许访问返回true,否则false;
onAccessDenied:表示当访问拒绝时是否已经处理了;如果返回true表示需要继续处理;如果返回false表示该拦截器实例已经处理了,将直接返回即可
org.apache.shiro.web.filter.authc.AuthenticatingFilter#isAccessAllowed
1 | protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) { |
org.apache.shiro.web.filter.authc.AuthenticationFilter#isAccessAllowed
1 | protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) { |
1 | protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception { |
login.jsp也会被拦截,执行到这里然后访问login.jsp,
再然后post请求这个url,就会执行executeLogin
org.apache.shiro.web.filter.authc.AuthenticatingFilter#executeLogin
1 | protected boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception { |
认证流程
1 | public void login(AuthenticationToken token) throws AuthenticationException { |
1 | public Subject login(Subject subject, AuthenticationToken token) throws AuthenticationException { |
org.apache.shiro.mgt.AuthenticatingSecurityManager#authenticate
1 | public AuthenticationInfo authenticate(AuthenticationToken token) { |
org.apache.shiro.authc.AbstractAuthenticator#authenticate
org.apache.shiro.authc.pam.ModularRealmAuthenticator#authenticate
模板方法模式
1 | protected AuthenticationInfo doAuthenticate(AuthenticationToken authenticationToken) throws AuthenticationException { |
1 | protected AuthenticationInfo doMultiRealmAuthentication(Collection<Realm> realms, AuthenticationToken token) { |
1 | public final AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { |
eg:自定义realmA实现AuthenticatingRealm
1 | public class ShiroRealmA extends AuthenticatingRealm { |
授权流程
perms(PermissionsAuthorizationFilter.class) :url是否有权限
roles(RolesAuthorizationFilter.class), :url是否有该角色
1 | public boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws IOException { |
ModularRealmAuthorizer.isPermitted
1 | public boolean isPermitted(PrincipalCollection principals, String permission) { |
1 | public boolean isPermitted(String permission) { |
1 | public boolean isPermitted(PrincipalCollection principals, String permissionString) { |
1 | public boolean isPermitted(PrincipalCollection principals, String permission) { |
1 | protected AuthorizationInfo getAuthorizationInfo(PrincipalCollection principals) { |
ModularRealmAuthorizer.isPermittedAll
AuthorizationFilter#onAccessDenied
1 | protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws IOException { |
FormAuthenticationFilter
Onceperrequestfilter#doFilter
adviceFilter#doFilterInternal
AdviceFilter#preHandle true
AuthenticatingFilter#cleanup
FormAuthenticationFilter#onAccessDenied
1 | protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception { |
org.apache.shiro.web.filter.authc.AuthenticatingFilter#executeLogin
1 | protected boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception { |
go to 认证流程
PermissionsAuthorizationFilter
Onceperrequestfilter#doFilter
adviceFilter#doFilterInternal
PathMatchingFilter#preHandle
AccessControlFilter#onPreHandle
go to 授权流程
PermissionsAuthorizationFilter#isAccessAllowed
AuthorizationFilter#onAccessDenied
RolesAuthorizationFilter
与PermissionsAuthorizationFilter类似
UserFilter
是登录页面或者必须登录后获得principalCollection,才能通过
1 | protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) { |
1 | protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception { |
参考文献