在单Realm的基础上,进行如下内容的修改
原有的ShiroRealm.java:
1 package com.atguigu.shiro.realms; 2 3 import org.apache.shiro.authc.AuthenticationException; 4 import org.apache.shiro.authc.AuthenticationInfo; 5 import org.apache.shiro.authc.AuthenticationToken; 6 import org.apache.shiro.authc.LockedAccountException; 7 import org.apache.shiro.authc.SimpleAuthenticationInfo; 8 import org.apache.shiro.authc.UnknownAccountException; 9 import org.apache.shiro.authc.UsernamePasswordToken; 10 import org.apache.shiro.crypto.hash.SimpleHash; 11 import org.apache.shiro.realm.AuthenticatingRealm; 12 import org.apache.shiro.util.ByteSource; 13 14 public class ShiroRealm extends AuthenticatingRealm { 15 16 @Override 17 protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { 18 19 System.out.println("[ShiroRealm] doGetAuthenticationInfo"); 20 21 //1. 把AuthenticationToken 转换为 UsernamePasswordToken 22 UsernamePasswordToken upToken = (UsernamePasswordToken)token; 23 24 //2. 从UsernamePasswordToken 中来获取username 25 String username = upToken.getUsername(); 26 27 //3.调用数据库的方法,从数据库查询username 对应的用户记录 28 System.out.println("从数据库中获取username:" + username +" 所对应的用户信息"); 29 30 //4.若用户不存在可以抛出 UnknownAccountException 异常 31 if ("unknown".equals(username)) { 32 throw new UnknownAccountException("用户不存在"); 33 } 34 35 //5.根据用户信息的情况,决定是否抛出其它的 AuthenticationException 异常 36 if ("monster".equals(username)) { 37 throw new LockedAccountException("用户被锁定"); 38 } 39 40 //6.根据用户的情况,来构建 AuthenticationToken 对象并返回,通常使用的实现类为:SimpleAuthenticationInfo 41 //一下信息是从数据库中获取的 42 //1).principals:认证的实体信息,可以是username,也可以是数据表对应的实体类对象 43 Object principal = username; 44 //2).credentials:密码 45 Object hashedCredentials = null; //"fc1709d0a95a6be30bc5926fdb7f22f4"; 46 if ("admin".equals(username)) { 47 hashedCredentials = "038bdaf98f2037b31f1e75b5b4c9b26e"; 48 }else if("user".equals(username)) { 49 hashedCredentials = "098d2c478e9c11555ce2823231e02ec1"; 50 } 51 52 53 //3).realmName:当前realm 对象的name,调用父类的getName()方法即可 54 String realmName = getName(); 55 //4).盐值 56 //SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(principal, credential,realmName); 57 //因为用户名唯一,使用用户名作为盐值 58 ByteSource credentialsSalt = ByteSource.Util.bytes(username); 59 SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(principal, hashedCredentials, credentialsSalt, realmName); 60 return info; 61 } 62 63 public static void main(String[] args) { 64 String algorithmName = "MD5"; 65 Object password = "123456"; 66 Object salt = ByteSource.Util.bytes("admin"); 67 int hashIterations = 1024; 68 Object result = new SimpleHash(algorithmName, password, salt, hashIterations); 69 System.out.println(result); 70 } 71 72 }
添加SecondRealm.java:
1 package com.atguigu.shiro.realms; 2 3 import org.apache.shiro.authc.AuthenticationException; 4 import org.apache.shiro.authc.AuthenticationInfo; 5 import org.apache.shiro.authc.AuthenticationToken; 6 import org.apache.shiro.authc.LockedAccountException; 7 import org.apache.shiro.authc.SimpleAuthenticationInfo; 8 import org.apache.shiro.authc.UnknownAccountException; 9 import org.apache.shiro.authc.UsernamePasswordToken; 10 import org.apache.shiro.crypto.hash.SimpleHash; 11 import org.apache.shiro.realm.AuthenticatingRealm; 12 import org.apache.shiro.util.ByteSource; 13 14 public class SecondRealm extends AuthenticatingRealm { 15 16 @Override 17 protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { 18 19 System.out.println("[SecondRealm] doGetAuthenticationInfo"); 20 21 //1. 把AuthenticationToken 转换为 UsernamePasswordToken 22 UsernamePasswordToken upToken = (UsernamePasswordToken)token; 23 24 //2. 从UsernamePasswordToken 中来获取username 25 String username = upToken.getUsername(); 26 27 //3.调用数据库的方法,从数据库查询username 对应的用户记录 28 System.out.println("从数据库中获取username:" + username +" 所对应的用户信息"); 29 30 //4.若用户不存在可以抛出 UnknownAccountException 异常 31 if ("unknown".equals(username)) { 32 throw new UnknownAccountException("用户不存在"); 33 } 34 35 //5.根据用户信息的情况,决定是否抛出其它的 AuthenticationException 异常 36 if ("monster".equals(username)) { 37 throw new LockedAccountException("用户被锁定"); 38 } 39 40 //6.根据用户的情况,来构建 AuthenticationToken 对象并返回,通常使用的实现类为:SimpleAuthenticationInfo 41 //一下信息是从数据库中获取的 42 //1).principals:认证的实体信息,可以是username,也可以是数据表对应的实体类对象 43 Object principal = username; 44 //2).credentials:密码 45 Object hashedCredentials = null; //"fc1709d0a95a6be30bc5926fdb7f22f4"; 46 if ("admin".equals(username)) { 47 hashedCredentials = "ce2f6417c7e1d32c1d81a797ee0b499f87c5de06"; 48 }else if("user".equals(username)) { 49 hashedCredentials = "073d4c3ae812935f23cb3f2a71943f49e082a718"; 50 } 51 52 53 //3).realmName:当前realm 对象的name,调用父类的getName()方法即可 54 String realmName = getName(); 55 //4).盐值 56 //SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(principal, credential,realmName); 57 //因为用户名唯一,使用用户名作为盐值 58 ByteSource credentialsSalt = ByteSource.Util.bytes(username); 59 SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(principal, hashedCredentials, credentialsSalt, realmName); 60 return info; 61 } 62 63 public static void main(String[] args) { 64 String algorithmName = "SHA1"; 65 Object password = "123456"; 66 Object salt = ByteSource.Util.bytes("admin"); 67 int hashIterations = 1024; 68 Object result = new SimpleHash(algorithmName, password, salt, hashIterations); 69 System.out.println(result); 70 } 71 72 }
修改applicationContext.xml:
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 </bean> 21 22 <!-- Let's use some enterprise caching support for better performance. You can replace this with any enterprise 23 caching framework implementation that you like (Terracotta+Ehcache, Coherence, GigaSpaces, etc --> 24 25 <!-- 26 2.配置cacheManager 27 2.1 需要加入ehcache的jar包及配置文件 28 --> 29 <bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager"> 30 <!-- Set a net.sf.ehcache.CacheManager instance here if you already have one. If not, a new one 31 will be creaed with a default config: 32 <property name="cacheManager" ref="ehCacheManager"/> --> 33 <!-- If you don't have a pre-built net.sf.ehcache.CacheManager instance to inject, but you want 34 a specific Ehcache configuration to be used, specify that here. If you don't, a default 35 will be used.: --> 36 <property name="cacheManagerConfigFile" value="classpath:ehcache.xml"/> 37 </bean> 38 39 <!-- 将两个Realm配置到认证器中 --> 40 <bean id="authenticator" class="org.apache.shiro.authc.pam.ModularRealmAuthenticator"> 41 <property name="realms"> 42 <list> 43 <ref bean="jdbcRealm"/> 44 <ref bean="secondRealm"/> 45 </list> 46 </property> 47 </bean> 48 <!-- Used by the SecurityManager to access security data (users, roles, etc). 49 Many other realm implementations can be used too (PropertiesRealm, 50 LdapRealm, etc. --> 51 52 <!-- 53 3.配置Realm 54 3.1直接配置实现了com.atguigu.shiro.realms.ShiroRealm接口的bean 55 --> 56 <bean id="jdbcRealm" class="com.atguigu.shiro.realms.ShiroRealm"> 57 <!-- 配置MD5加密 --> 58 <property name="credentialsMatcher"> 59 <bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher"> 60 <!-- 指定加密方式为MD5 --> 61 <property name="hashAlgorithmName" value="MD5"></property> 62 <!-- 指定加密次数 --> 63 <property name="hashIterations" value="1024"></property> 64 </bean> 65 </property> 66 </bean> 67 68 <bean id="secondRealm" class="com.atguigu.shiro.realms.SecondRealm"> 69 <!-- 配置MD5加密 --> 70 <property name="credentialsMatcher"> 71 <bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher"> 72 <!-- 指定加密方式为MD5 --> 73 <property name="hashAlgorithmName" value="SHA1"></property> 74 <!-- 指定加密次数 --> 75 <property name="hashIterations" value="1024"></property> 76 </bean> 77 </property> 78 </bean> 79 80 <!-- ========================================================= 81 Shiro Spring-specific integration 82 ========================================================= --> 83 <!-- Post processor that automatically invokes init() and destroy() methods 84 for Spring-configured Shiro objects so you don't have to 85 1) specify an init-method and destroy-method attributes for every bean 86 definition and 87 2) even know which Shiro objects require these methods to be 88 called. --> 89 <!-- 90 4.配置LifecycleBeanPostProcessor,可以自动地来调用配置在Spring IOC容器中shiro bean的生命周期方法 91 --> 92 <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/> 93 94 <!-- Enable Shiro Annotations for Spring-configured beans. Only run after 95 the lifecycleBeanProcessor has run: --> 96 97 <!-- 98 5.启用IOC容器中使用shiro的注解,但必须在配置了LifecycleBeanPostProcessor之后才可以使用 99 --> 100 <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" 101 depends-on="lifecycleBeanPostProcessor"/> 102 <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"> 103 <property name="securityManager" ref="securityManager"/> 104 </bean> 105 106 <!-- Define the Shiro Filter here (as a FactoryBean) instead of directly in web.xml - 107 web.xml uses the DelegatingFilterProxy to access this bean. This allows us 108 to wire things with more control as well utilize nice Spring things such as 109 PropertiesPlaceholderConfigurer and abstract beans or anything else we might need: --> 110 111 <!-- 112 6.配置ShiroFilter 113 6.1 id必须和web.xml文件中配置的DelegatingFilterProxy的 <filter-name> 一致 114 若不一致,则会抛出:NoSuchBeanDefinitionException. 因为 Shiro 会来 IOC 容器中查找和 <filter-name> 名字对应的 filter bean. 115 6.2 116 --> 117 <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> 118 <property name="securityManager" ref="securityManager"/> 119 <property name="loginUrl" value="/login.jsp"/> 120 <property name="successUrl" value="/list.jsp"/> 121 <property name="unauthorizedUrl" value="/unauthorized.jsp"/> 122 123 <!-- 124 配置哪些页面需要受保护 125 以及访问这些页面需要的权限 126 1). anon 可以被匿名访问 127 2). authc 必须认证(即登录)后才可以访问的页面 128 3). logout 登出 129 --> 130 <property name="filterChainDefinitions"> 131 <value> 132 /login.jsp = anon 133 /shiro/login = anon 134 /shiro/logout = logout 135 # everything else requires authentication: 136 /** = authc 137 </value> 138 </property> 139 </bean> 140 </beans>