认证流程图解:
身份认证流程
- 1、首先调用Subject.login(token) 进行登录,其会自动委托给SecurityManager
- 2、SecurityManager负责真正的身份验证逻辑;它会委托给Authenticator 进行身份验证;
- 3、Authenticator 才是真正的身份验证者,ShiroAPI 中核心的身份认证入口点,此处可以自定义插入自己的实现;
- 4、Authenticator 可能会委托给相应的AuthenticationStrategy进行多Realm 身份验证,默认ModularRealmAuthenticator会调用AuthenticationStrategy进行多Realm 身份验证;
- 5、Authenticator 会把相应的token 传入Realm,从Realm 获取身份验证信息,如果没有返回/抛出异常表示身份验证失败了。此处可以配置多个Realm,将按照相应的顺序及策略进行访问。
Realm
- Realm:Shiro从Realm 获取安全数据(如用户、角色、权限),即SecurityManager要验证用户身份,那么它需要从Realm 获取相应的用户进行比较以确定用户身份是否合法;也需要从Realm得到用户相应的角色/权限进行验证用户是否能进行操作
- Realm接口如下:
- 一般继承AuthorizingRealm(授权)即可;其继承了AuthenticatingRealm(即身份验证),而且也间接继承了CachingRealm(带有缓存实现)。
- Realm 的继承关系:
Authenticator
- Authenticator 的职责是验证用户帐号,是ShiroAPI 中身份验证核心的入口点:如果验证成功,将返回AuthenticationInfo验证信息;此信息中包含了身份及凭证;如果验证失败将抛出相应的AuthenticationException异常
- SecurityManager接口继承了Authenticator,另外还有一个ModularRealmAuthenticator实现,其委托给多个Realm 进行验证,验证规则通过AuthenticationStrategy接口指定
AuthenticationStrategy
- AuthenticationStrategy接口的默认实现:
- FirstSuccessfulStrategy:只要有一个Realm 验证成功即可,只返回第一个Realm 身份验证成功的认证信息,其他的忽略;
- AtLeastOneSuccessfulStrategy:只要有一个Realm验证成功即可,和FirstSuccessfulStrategy不同,将返回所有Realm身份验证成功的认证信息;
- AllSuccessfulStrategy:所有Realm验证成功才算成功,且返回所有Realm身份验证成功的认证信息,如果有一个失败就失败了。
- ModularRealmAuthenticator默认是AtLeastOneSuccessfulStrategy策略
代码示例:
1 <!-- 将两个Realm配置到认证器中 --> 2 <bean id="authenticator" class="org.apache.shiro.authc.pam.ModularRealmAuthenticator"> 3 <property name="realms"> 4 <list> 5 <ref bean="jdbcRealm"/> 6 <ref bean="secondRealm"/> 7 </list> 8 </property> 9 <!-- 添加AllSuccessfulStrategy:所有Realm验证成功才算成功,且返回所有Realm身份验证成功的认证信息,如果有一个失败就失败了。 --> 10 <property name="authenticationStrategy"> 11 <bean class="org.apache.shiro.authc.pam.AllSuccessfulStrategy"></bean> 12 </property> 13 </bean>
最终,代码位置要迁移,修改后代码如下:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> 5 6 <!-- ========================================================= 7 Shiro Core Components - Not Spring Specific 8 ========================================================= --> 9 <!-- Shiro's main business-tier object for web-enabled applications 10 (use DefaultSecurityManager instead when there is no web environment)--> 11 <!-- 12 1.配置SecurityManager! 13 --> 14 <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> 15 <property name="cacheManager" ref="cacheManager"/> 16 <!-- 单个Realm --> 17 <!-- <property name="realm" ref="jdbcRealm"/> --> 18 <!-- 多Realm --> 19 <property name="authenticator" ref="authenticator"/> 20 <!-- 将两个Realm配置到认证器中 --> 21 <property name="realms"> 22 <list> 23 <ref bean="jdbcRealm"/> 24 <ref bean="secondRealm"/> 25 </list> 26 </property> 27 </bean> 28 29 <!-- Let's use some enterprise caching support for better performance. You can replace this with any enterprise 30 caching framework implementation that you like (Terracotta+Ehcache, Coherence, GigaSpaces, etc --> 31 32 <!-- 33 2.配置cacheManager 34 2.1 需要加入ehcache的jar包及配置文件 35 --> 36 <bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager"> 37 <!-- Set a net.sf.ehcache.CacheManager instance here if you already have one. If not, a new one 38 will be creaed with a default config: 39 <property name="cacheManager" ref="ehCacheManager"/> --> 40 <!-- If you don't have a pre-built net.sf.ehcache.CacheManager instance to inject, but you want 41 a specific Ehcache configuration to be used, specify that here. If you don't, a default 42 will be used.: --> 43 <property name="cacheManagerConfigFile" value="classpath:ehcache.xml"/> 44 </bean> 45 46 47 <bean id="authenticator" class="org.apache.shiro.authc.pam.ModularRealmAuthenticator"> 48 <!-- AllSuccessfulStrategy:所有Realm验证成功才算成功,且返回所有Realm身份验证成功的认证信息,如果有一个失败就失败了。 --> 49 <property name="authenticationStrategy"> 50 <bean class="org.apache.shiro.authc.pam.AllSuccessfulStrategy"></bean> 51 </property> 52 </bean> 53 <!-- Used by the SecurityManager to access security data (users, roles, etc). 54 Many other realm implementations can be used too (PropertiesRealm, 55 LdapRealm, etc. --> 56 57 <!-- 58 3.配置Realm 59 3.1直接配置实现了com.atguigu.shiro.realms.ShiroRealm接口的bean 60 --> 61 <bean id="jdbcRealm" class="com.atguigu.shiro.realms.ShiroRealm"> 62 <!-- 配置MD5加密 --> 63 <property name="credentialsMatcher"> 64 <bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher"> 65 <!-- 指定加密方式为MD5 --> 66 <property name="hashAlgorithmName" value="MD5"></property> 67 <!-- 指定加密次数 --> 68 <property name="hashIterations" value="1024"></property> 69 </bean> 70 </property> 71 </bean> 72 73 <bean id="secondRealm" class="com.atguigu.shiro.realms.SecondRealm"> 74 <!-- 配置MD5加密 --> 75 <property name="credentialsMatcher"> 76 <bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher"> 77 <!-- 指定加密方式为MD5 --> 78 <property name="hashAlgorithmName" value="SHA1"></property> 79 <!-- 指定加密次数 --> 80 <property name="hashIterations" value="1024"></property> 81 </bean> 82 </property> 83 </bean> 84 85 <!-- ========================================================= 86 Shiro Spring-specific integration 87 ========================================================= --> 88 <!-- Post processor that automatically invokes init() and destroy() methods 89 for Spring-configured Shiro objects so you don't have to 90 1) specify an init-method and destroy-method attributes for every bean 91 definition and 92 2) even know which Shiro objects require these methods to be 93 called. --> 94 <!-- 95 4.配置LifecycleBeanPostProcessor,可以自动地来调用配置在Spring IOC容器中shiro bean的生命周期方法 96 --> 97 <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/> 98 99 <!-- Enable Shiro Annotations for Spring-configured beans. Only run after 100 the lifecycleBeanProcessor has run: --> 101 102 <!-- 103 5.启用IOC容器中使用shiro的注解,但必须在配置了LifecycleBeanPostProcessor之后才可以使用 104 --> 105 <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" 106 depends-on="lifecycleBeanPostProcessor"/> 107 <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"> 108 <property name="securityManager" ref="securityManager"/> 109 </bean> 110 111 <!-- Define the Shiro Filter here (as a FactoryBean) instead of directly in web.xml - 112 web.xml uses the DelegatingFilterProxy to access this bean. This allows us 113 to wire things with more control as well utilize nice Spring things such as 114 PropertiesPlaceholderConfigurer and abstract beans or anything else we might need: --> 115 116 <!-- 117 6.配置ShiroFilter 118 6.1 id必须和web.xml文件中配置的DelegatingFilterProxy的 <filter-name> 一致 119 若不一致,则会抛出:NoSuchBeanDefinitionException. 因为 Shiro 会来 IOC 容器中查找和 <filter-name> 名字对应的 filter bean. 120 6.2 121 --> 122 <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> 123 <property name="securityManager" ref="securityManager"/> 124 <property name="loginUrl" value="/login.jsp"/> 125 <property name="successUrl" value="/list.jsp"/> 126 <property name="unauthorizedUrl" value="/unauthorized.jsp"/> 127 128 <!-- 129 配置哪些页面需要受保护 130 以及访问这些页面需要的权限 131 1). anon 可以被匿名访问 132 2). authc 必须认证(即登录)后才可以访问的页面 133 3). logout 登出 134 --> 135 <property name="filterChainDefinitions"> 136 <value> 137 /login.jsp = anon 138 /shiro/login = anon 139 /shiro/logout = logout 140 # everything else requires authentication: 141 /** = authc 142 </value> 143 </property> 144 </bean> 145 </beans>