web.xml 註冊filterjava
<!-- shiro 安全過濾器 --> <filter> <filter-name>shiroFilter</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> <async-supported>true</async-supported> <init-param> <param-name>targetFilterLifecycle</param-name> <param-value>true</param-value> </init-param> </filter>
此處只是配置一個shiroFilterFactory,真正的filter在spring中配置git
ps:這樣配置將本來須要配置在web.xml中的filter配置在了spring.xml中github
spring-config-shiro.xmlweb
<!-- Shiro的Web過濾器 --> <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <property name="securityManager" ref="securityManager"/> <property name="loginUrl" value="/login"/> <property name="filters"> <util:map> <!--shiroFilter--> <entry key="authc" value-ref="formAuthenticationFilter"/> <entry key="sysUser" value-ref="sysUserFilter"/> </util:map> </property> <property name="filterChainDefinitions"> <value> /login = authc /logout = logout /authenticated = authc /** = user,sysUser </value> </property> </bean>
其中配置了formAuthenticationFilterspring
public class FormAuthenticationFilter extends AuthenticatingFilter {}
//MyFormAuthenticationFilter.java public class MyFormAuthenticationFilter extends FormAuthenticationFilter { @Override protected boolean onAccessDenied(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception { if(request.getAttribute(getFailureKeyAttribute()) != null) { return true; } return super.onAccessDenied(request, response, mappedValue); } }
若是以前的filter(驗證碼filter)錯誤了,再也不繼續執行 return true;apache
以前沒錯則執行onAccessDenied()。 ShiroFilterFactoryBean 具備攔截filter的能力,filters首先按web.xml配置的順序執行,執行到ShiroFilterFactoryBean,註冊shiro本身的filters,率先執行本身的filters,以後再接着執行web.xml中的filter安全
在FormAuthenticationFilter.onAccessDenied()app
-> AuthenticatingFilter.executeLogin()執行登錄。async
AuthenticatingFilter提供create(request,response)ide
AccessControlFilter提供getSubject(request,response)
-> (DelegatingSubject)subject.login(token)
-> DelegatingSubject#securityManager.login() 登錄後對subject中的屬性作一些賦值
-> AuthenticatingSecurityManager#authenticator.authenticate()
-> ModularRealmAuthenticator#realms.getAuthenticationInfo()
最終落到realms上
<bean id="credentialsMatcher" class="com.github.zhangkaitao.shiro.chapter16.credentials.RetryLimitHashedCredentialsMatcher"> <constructor-arg ref="cacheManager"/> <property name="hashAlgorithmName" value="md5"/> <property name="hashIterations" value="2"/> <property name="storedCredentialsHexEncoded" value="true"/> </bean> <!-- Realm實現 --> <bean id="userRealm" class="com.github.zhangkaitao.shiro.chapter16.realm.UserRealm"> <property name="credentialsMatcher" ref="credentialsMatcher"/> <property name="cachingEnabled" value="false"/> <!--<property name="authenticationCachingEnabled" value="true"/>--> <!--<property name="authenticationCacheName" value="authenticationCache"/>--> <!--<property name="authorizationCachingEnabled" value="true"/>--> <!--<property name="authorizationCacheName" value="authorizationCache"/>--> </bean>
realm能夠配置credentialsMatcher 在哪用?
//ModularRealmAuthenticator.java protected AuthenticationInfo doMultiRealmAuthentication(Collection<Realm> realms, AuthenticationToken token) { //策略 AuthenticationStrategy strategy = getAuthenticationStrategy(); AuthenticationInfo aggregate = strategy.beforeAllAttempts(realms, token); if (log.isTraceEnabled()) { log.trace("Iterating through {} realms for PAM authentication", realms.size()); } for (Realm realm : realms) { aggregate = strategy.beforeAttempt(realm, token, aggregate); if (realm.supports(token)) { log.trace("Attempting to authenticate token [{}] using realm [{}]", token, realm); AuthenticationInfo info = null; Throwable t = null; try { info = realm.getAuthenticationInfo(token); //試用CredentialsMatcher匹配 } catch (Throwable throwable) { t = throwable; if (log.isDebugEnabled()) { String msg = "Realm [" + realm + "] threw an exception during a multi-realm authentication attempt:"; log.debug(msg, t); } } aggregate = strategy.afterAttempt(realm, token, info, aggregate, t); } else { log.debug("Realm [{}] does not support token {}. Skipping realm.", realm, token); } } aggregate = strategy.afterAllAttempts(token, aggregate); return aggregate; }