【Shiro权限管理】21.Shiro缓存

注:该系列所有测试均在之前创建的Shiro3的Web工程的基础上。
在使用Shiro框架进行授权或者权限管理时,可以利用Shiro框架的缓存特性来提高系统的性能。那么如何
来实现Shiro的缓存效果呢?

Shiro中提供了一个CacheManagerAware接口,实现此接口的类都可以进行缓存的一些基础操作。
同理也即是说Realm实现了CacheManagerAware接口就可以操作缓存。

当我们的Realm实现了CacheManagerAware接口或继承了实现CacheManagerAware接口的父类的时候,
在Shiro内部有组件(DefaultSecurityManager)会自动检测相应的对象(如Realm)是否实现了
CacheManagerAware并自动注入相应的CacheManager。

Shiro提供了一个叫CachingRealm的Realm类,它实现了CacheManagerAware接口,
所以该Realm提供了缓存的一些基础实现; 

那么我们自己创建的,继承AuthorizingRealm类的自定义Realm其实是可以直接操作缓存的,因为
自定义Realm继承的AuthorizingRealm类继承了AuthenticatingRealm类,而AuthenticatingRealm类
继承了CachingRealm类:

正如上面所说,CachingRealm类实现了CacheManagerAware接口,可以操作缓存:

所以说我们的Realm是有缓存的。

下面我们通过一个授权操作来看一下在Realm缓存的效果。
首先回顾一下名为“Shiro3”的Web工程中的“ShiroRealm”类:
package com.test.shiro.realms;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;

import com.test.shiro.po.User;
public class ShiroRealm extends AuthorizingRealm{
	
	private static Map<String,User> userMap = new HashMap<String,User>();
	static{
		//使用Map模拟数据库获取User表信息
		userMap.put("administrator", new User("administrator","5703a57069fce1f17882d283132229e0",false));//密码明文:aaa123
		userMap.put("jack", new User("jack","43e66616f8730a08e4bf1663301327b1",false));//密码明文:aaa123
		userMap.put("tom", new User("tom","3abee8ced79e15b9b7ddd43b95f02f95",false));//密码明文:bbb321
		userMap.put("jean", new User("jean","1a287acb0d87baded1e79f4b4c0d4f3e",true));//密码明文:ccc213
	}

	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(
			AuthenticationToken token) throws AuthenticationException {
		System.out.println("[ShiroRealm]");
		//1.把AuthenticationToken转换为UsernamePasswordToken
		UsernamePasswordToken userToken = (UsernamePasswordToken) token;
		
		//2.从UsernamePasswordToken中获取username
		String username = userToken.getUsername();
		
		//3.调用数据库的方法,从数据库中查询Username对应的用户记录
		System.out.println("从数据看中获取UserName为"+username+"所对应的信息。");
		//Map模拟数据库取数据
		User u = userMap.get(username);
		
		//4.若用户不行存在,可以抛出UnknownAccountException
		if(u==null){
			throw new UnknownAccountException("用户不存在");
		}
		
		//5.若用户被锁定,可以抛出LockedAccountException
		if(u.isLocked()){
			throw new LockedAccountException("用户被锁定");
		}
		
		//7.根据用户的情况,来构建AuthenticationInfo对象,通常使用的实现类为SimpleAuthenticationInfo
		//以下信息是从数据库中获取的
		//1)principal:认证的实体信息,可以是username,也可以是数据库表对应的用户的实体对象
		Object principal = u.getUsername();
		//2)credentials:密码
		Object credentials = u.getPassword();
		//3)realmName:当前realm对象的name,调用父类的getName()方法即可
		String realmName = getName();
		//4)credentialsSalt盐值
		ByteSource credentialsSalt = ByteSource.Util.bytes(principal);//使用账号作为盐值
		
		SimpleAuthenticationInfo info = null; //new SimpleAuthenticationInfo(principal,credentials,realmName);
		info = new SimpleAuthenticationInfo(principal, credentials, credentialsSalt, realmName);
		return info;
	}

	//给Shiro的授权验证提供授权信息
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(
			PrincipalCollection principals) {
		//1.从principals中获取登录用户的信息
		Object principal = principals.getPrimaryPrincipal();
		
		//2.利用登录用户的信息获取当前用户的角色(有数据库的话,从数据库中查询)
		Set<String> roles = new HashSet<String>();//放置用户角色的set集合(不重复)
		roles.add("user");//放置所有用户都有的普通用户角色
		if("administrator".equals(principal)){
			roles.add("admin");//当账号为administrator时,添加admin角色
		}
		
		//3.创建SimpleAuthorizationInfo,并设置其roles属性
		SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(roles);
		
		//4.返回SimpleAuthorizationInfo对象
		return info;
	}
}
然后我们在doGetAuthorizationInfo方法的“Object principal = principals.getPrimaryPrincipal();”处
打断点,然后运行Web程序,在登录界面登录账号为“jack”的账户:

然后进入了断点:


这说明是第一次登录,此时系统还没有授权信息的缓存,会调用doGetAuthorizationInfo的方法获取用户的授权
信息。然后再一次访问页面之后,因为上一次缓存了用户的授权信息,所以就不会再进入doGetAuthorizationInfo
方法的断点了。

而前面说到,Shiro内部组件DefaultSecurityManager会自动检测相应的对象(如Realm)是否实现了
CacheManagerAware并自动注入相应的CacheManager。那么也就是说如果不注入CacheManager就无法实现
缓存的效果,所以在Web工程的Spring配置文件application.xml中是配置了CacheManager的:
<!--1. 配置 SecurityManager-->     
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
    <property name="cacheManager" ref="cacheManager"/>
    <property name="authenticator" ref="authenticator"/>
    <property name="realms">
        <list>
            <ref bean="shiroRealm"/>
            <ref bean="secordRealm"/>
        </list>
    </property>
</bean>

<!--  
2. 配置 CacheManager. 
2.1 需要加入 ehcache 的 jar 包及配置文件. 
-->     
<bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
    <property name="cacheManagerConfigFile" value="classpath:ehcache.xml"/> 
</bean>
如果我们将<property name="cacheManager" ref="cacheManager"/>以及下面相关Bean配置去掉,那么
Realm将失去缓存效果,也就是说每一次进入系统的页面时,都需要去访问doGetAuthorizationInfo方法
来获取缓存,这种操作是十分耗费性能的,这也是缓存存在的意义。

实际上在配置Realm的时候,还可以设置Realm缓存的一些属性:


而同意我们可以在ehcache配置文件ehcache.xml中可以设置这些缓存属性:
<ehcache>
    <diskStore path="java.io.tmpdir"/>
    
    <!-- 授权的时候使用的缓存策略 -->
    <cache name="authorizationCache"
           eternal="false"
           timeToIdleSeconds="3600"
           timeToLiveSeconds="0"
           overflowToDisk="false"
           statistics="true">
    </cache>

    <!-- 认证的时候使用的缓存策略 -->
    <cache name="authenticationCache"
           eternal="false"
           timeToIdleSeconds="3600"
           timeToLiveSeconds="0"
           overflowToDisk="false"
           statistics="true">
    </cache>
<ehcache>
而Session也可以使用缓存,实现方式大致相同,其也是通过实现CacheManagerAware接口或继承实现
CacheManagerAware接口的父类来获取缓存的。
如SecurityManager实现了SessionSecurityManager,其会判断SessionManager是否实现了CacheManagerAware接口,
如果实现了会把CacheManager设置给它。
SessionManager也会判断相应的SessionDAO(如继承 自CachingSessionDAO)是否实现了CacheManagerAware,
如果实现了会把CacheManager设置给它。
设置了缓存的SessionManager,查询时会先查缓存,如果找不到才查数据库。

实际开发时,通常会使用Redis来作为Session的缓存。

转载请注明出处:http://blog.csdn.net/acmman/article/details/78989066

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
### 回答1: Spring Boot是基于Spring框架的快速开发应用程序的工具,而Shiro则是一个强大且灵活的Java安全框架。将Spring Boot与Shiro结合使用可以实现权限管理的功能。 首先需要在Spring Boot项目中引入相关依赖,包括Spring Boot的依赖和Shiro的依赖。可以在pom.xml文件中添加如下依赖: ``` <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.7.1</version> </dependency> ``` 接下来,需要配置Shiro的配置类。可以创建一个继承自org.apache.shiro.web.mgt.DefaultWebSecurityManager的类,并在该类中配置Shiro的相关信息,包括认证器和授权器。 认证器负责验证用户的身份,可以使用Shiro提供的Realm来实现自定义的身份验证逻辑。授权器负责判断用户是否有权限执行某个操作,可以使用Shiro提供的Permission类来实现权限的控制。 然后,需要为Spring Boot应用程序配置Shiro过滤器链。可以使用Shiro的FilterChainDefinitionMap类来配置URL与权限的映射关系。可以在一个继承自org.apache.shiro.web.env.AbstractWebEnvironment的类中配置这些过滤器链。 最后,在Spring Boot应用程序的入口类中启动Shiro配置。在main()方法中,可以使用org.apache.shiro.SecurityUtils类的setSecurityManager()方法来设置Shiro的安全管理器。 完成以上步骤后,Spring Boot应用程序就集成了Shiro权限管理功能。可以通过编写相应的Controller和页面来测试权限管理的效果。 总之,通过将Spring Boot与Shiro结合使用,可以实现权限管理的功能。通过配置Shiro的相关类和过滤器链,以及编写自定义的Realm和Permission,可以实现身份验证和权限控制的逻辑。 ### 回答2: Spring Boot是一个用于创建独立的、基于Spring的应用程序的框架。Shiro是一个强大的Java安全框架,提供了身份认证、授权、加密等安全功能。下面是使用Spring Boot集成Shiro权限管理的步骤和注意事项。 1. 添加依赖:在Maven或Gradle中添加Spring Boot和Shiro的依赖项。 2. 创建Shiro配置类:创建一个继承自`org.apache.shiro.spring.config.ShiroAnnotationProcessorConfiguration`的配置类。在该类中配置Shiro的安全相关属性,比如加密算法、身份认证方式等。 3. 创建用户实体类:创建表示用户的实体类,并为其添加相关属性,如用户名、密码等。 4. 创建用户服务类:创建一个用户服务类,用于处理用户相关的操作,如用户注册、查询用户等。 5. 创建Realm类:创建一个继承自`org.apache.shiro.realm.AuthorizingRealm`的自定义Realm类。在该类中,实现身份认证和授权的逻辑。 6. 配置Shiro过滤器:在`application.properties`文件中配置Shiro的过滤器链,指定URL与权限之间的对应关系。 7. 创建Controller类:创建一个Controller类,用于处理用户请求。在该类中,通过`@RequiresRoles`和`@RequiresPermissions`等注解为方法添加授权需求。 8. 启动应用程序:使用Spring Boot的注解启动应用程序,让Spring Boot自动配置并启用Shiro。 注意事项: - 在配置Shiro时,需要根据实际需要选择适当的安全策略、加密算法和认证方式。 - 在自定义Realm类中,需要根据实际需求进行身份认证和授权的实现。 - 在通过Shiro注解为方法添加授权需求时,需要确保用户已经成功登录。 - 需要根据实际业务需求,合理配置Shiro的过滤器链,以获得所需的权限控制效果。 总之,使用Spring Boot集成Shiro权限管理可以方便地实现应用程序的安全认证和授权功能。通过配置Shiro的相关属性和自定义Realm类,可以实现灵活的权限管理,保护应用程序的安全。 ### 回答3: Spring Boot集成Shiro权限管理是一种常用的方式,可以实现安全的身份验证和授权功能。以下是一个简单的步骤,来演示如何实现这个集成。 第一步,导入相关依赖。在pom.xml文件中添加以下依赖项: ``` <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring-boot-web-starter</artifactId> <version>1.7.1</version> </dependency> ``` 第二步,编写Shiro的配置文件。创建一个类,命名为ShiroConfig,并使用@Configuration注解将其声明为一个配置类。在配置类中,使用@RequiresPermissions注解来定义URL的访问权限,使用@Bean注解来创建ShiroFilterFactoryBean和DefaultWebSecurityManager等Bean。 第三步,创建一个自定义的Realm类。这个类需要继承自AuthenticatingRealm,并实现其中的认证和授权方法。在认证方法中,需要根据用户名和密码来进行验证用户的身份。在授权方法中,需要判断用户是否具有访问某个URL的权限。 第四步,在Spring Boot的启动类中,添加@EnableCaching注解来启用缓存功能。这样可以提高系统的性能。 第五步,编写Controller类。在Controller中,使用@RequiresPermissions注解来定义URL的访问权限。在方法中,可以使用Subject进行身份验证和授权操作。 最后,启动应用程序。通过访问配置的URL,可以验证是否成功实现了Shiro权限管理功能。 通过以上步骤,我们可以实现Spring Boot集成Shiro权限管理。这样就可以在应用程序中实现安全的身份验证和授权功能,确保只有具备相应权限的用户可以访问指定的URL。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

光仔December

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值