shiro框架基础

1.shiro简介

Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码和会话管理。

官网:shiro.apache.org

shiro作用:验证用户、对用户执行访问控制、可以使用多个数据库、单点登录功能(SSO

 

shiro框架认证流程/原理(划重点)

 

Application Code:应用程序代码,由开发人员负责开发的(action)

Subject:框架提供的接口,代表当前用户对象(当前的登陆对象)

SecurityManager:框架提供的接口,代表安全管理器对象(核心对象)

Realm:可以开发人员编写,框架也提供一些,类似于DAO,用于访问权限数据(自己书写的校验对象)

扫描二维码关注公众号,回复: 3906438 查看本文章

 

2.shiro的使用

1>maven引入shiro依赖

		<!-- 引入shiro框架的依赖 -->
		<dependency>
			<groupId>org.apache.shiro</groupId>
			<artifactId>shiro-all</artifactId>
			<version>1.2.2</version>
		</dependency>

2>在web.xml中配置spring框架提供的用于整合shiro框架的过滤器(位置要在struts2的过滤器前面)

  <!-- 配置spring框架提供的用于整合shiro框架的过滤器 -->
  <filter>
  	<filter-name></filter-name><!-- shiroFilter是指定名称,要在applicationContext.xml中配置 -->
  	<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
  </filter>
  <filter-mapping>
  	<filter-name>shiroFilter</filter-name>
  	<url-pattern>/*</url-pattern>
  </filter-mapping>

3>在spring中配置bean,id为shiroFilter

	<!-- 配置shiro框架过滤工厂bean -->
	<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
		<!-- 注入安全管理器对象 -->
		<property name="securityManager" ref="securityManager"></property>
			<!-- 注入相关页面访问URL -->
		<property name="loginUrl" value="/login.jsp"/><!-- 登陆页面 -->
		<property name="successUrl" value="/index.jsp"/><!-- 首页 -->
		<property name="unauthorizedUrl" value="/unauthorized.jsp"/><!-- 没有权限时提示页面 -->
		<!--shiro权限控制方式1:注入URL拦截规则 -->
		<property name="filterChainDefinitions">
			<value>
				/css/** = anon
				/js/** = anon
				/images/** = anon
				/validatecode.jsp* = anon
				/login.jsp = anon
				/userAction_login.action = anon
				/page_base_staff.action = perms["staff-list"]<!--访问此路径时必须要有“staff-list权限” -->
				/* = authc
			</value>
		</property>
	</bean>
	
	<!-- 注册安全管理对象 -->
	<bean name="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
		<property name="realm" ref="bosRealm"></property>
	</bean>

	<!-- 注册realm -->
	<bean name="bosRealm" class="com.imwj.bos.realm.BOSRealm"></bean>

框架提供的过滤器

anon:无需认证、authc:认证过、perms:需要指定权限

 

4>UserAction中的login方法,使用shiro提供的方式

	public String login() throws Exception {
		//得到session域中的验证码
		String validatecode = (String) ServletActionContext.getRequest().getSession().getAttribute("key");
		//先判断验证码是否输入正确
		if(StringUtils.isNotBlank(checkcode) && validatecode.equals(checkcode)){
			//输入的验证码正确
			//使用shiro框架提供的方式进行认证
			Subject subject = SecurityUtils.getSubject();//获得当前登陆的用户对象,现在的状态未“未认证”
			//用户名密码令牌
			AuthenticationToken token = new UsernamePasswordToken(model.getUsername(), MD5Utils.md5(model.getPassword()));
			try {
				subject.login(token)//此处会跳转到我们所创建的realm
			} catch (UnknownAccountException e) {
				this.addActionError("用户名不存在");
				return LOGIN;
			} catch (IncorrectCredentialsException e) {
				this.addActionError("密码输入错误");
				return LOGIN;
			}
			User user = (User) subject.getPrincipal();
			ServletActionContext.getRequest().getSession().setAttribute("loginUser", user);
			return HOME;
		}else{
			//验证码输入不正确
			this.addActionError("验证码输入错误");
			return LOGIN;
		}
	}

5>自定义realm,并注入给安全管理器

public class BOSRealm extends AuthorizingRealm{
	
	@Autowired
	private IUserDao userDao;
	
	//认证方法
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
		UsernamePasswordToken mytoken = (UsernamePasswordToken) token;
		String username = mytoken.getUsername();
		//根据用户名查询数据库中的密码
		User user = userDao.findUsernameByUserName(username);
		if(user == null){
			//用户名不存在
			return null;
		}
		//如果能够查询到,再由框架比对数据中查询到的密码和页面提交的密码是否一致
		AuthenticationInfo info = new SimpleAuthenticationInfo(user, user.getPassword(), this.getName());
		return info;
	}
	
	//授权方法
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0) {
		SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
		info.addStringPermission("staff-list");//授予当前用户“staff-list”权限
		
		//TODO 后期需要修改为根据当前登录用户查询数据库,获取实际对应的权限
		return info;
	}
}

 

 

3.shiro框架提供的四种权限控制方式

URL拦截权限控制(基于过滤器实现)、方法注解权限控制(基于代理技术实现)、页面标签权限控制(标签技术实现)、代码级别权限控制(作了解,基于代理技术)

1>URL拦截权限控制,前面已经实现

			<value>
				/css/** = anon
				/js/** = anon
				/images/** = anon
				/validatecode.jsp* = anon
				/login.jsp = anon
				/userAction_login.action = anon
				/page_base_staff.action = perms["staff-list"]<!--访问此路径时必须要有“staff-list权限” -->
				/* = authc
			</value>

 

2>方法注解控制@RequiresPermissions("staff-delete")

	<!-- 开启shiro框架注解支持 -->
	<bean id="defaultAdvisorAutoProxyCreator" 
		class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator">
			<!-- 必须使用cglib方式为Action对象创建代理对象 -->
		<property name="proxyTargetClass" value="true"/>
	</bean>
	
	<!-- 配置shiro框架提供的切面类,用于创建代理对象 -->
	<bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"/>
        <!-- action中 -->
	@RequiresPermissions("staff-delete")//执行这个方法需要当前的登陆用户拥有staff-delete的权限
	public String deleteBatch(){

权限不足时会抛出异常,所以我们做一个全局异常处理

		<!-- 全局结果集配置 -->
		<global-results>
			<result name="login">/login.jsp</result>
			<result name="unauthorized">/unauthorized.jsp</result>
		</global-results>
		
		<!-- 全局异常捕获 -->
		<global-exception-mappings>
			<!-- 权限不足异常 -->
			<exception-mapping result="unauthorized" exception="org.apache.shiro.authz.UnauthorizedException"/>
		</global-exception-mappings>

 

3>使用shiro提供的页面标签进行权限控制:<shiro:hasPermission name="staff-delete">

在jsp中引入shiro的标签库

<%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>

将需要权限控制的按钮(比如删除)放置在shiro标签中:js代码也可以

<shiro:hasPermission name="staff-delete"> </shiro:hasPermission>

4>总结:使用shiro框架进行权限控制时,使用前三种权限控制混合的方式来达到权限控制的目的

 

4.shiro中的授权方法(划重点)

	//授权方法
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
		//获取当前登录用户对象
		User user = (User) SecurityUtils.getSubject().getPrincipal();
		//User user2 = (User) principals.getPrimaryPrincipal();
		// 根据当前登录用户查询数据库,获取实际对应的权限
		List<Function> list = null;
		if(user.getUsername().equals("admin")){//超级管理员内置用户,查询所有权限数据
			DetachedCriteria detachedCriteria = DetachedCriteria.forClass(Function.class);
			list = functionDao.findByCriteria(detachedCriteria);
		}else{//普通用户,查询对应的权限数据
			list = functionDao.findFunctionListByUserId(user.getId());
		}
		for (Function function : list) {
			info.addStringPermission(function.getCode());
		}
		return info;
	}

获取当前登陆用户对象:User user = (User) SecurityUtils.getSubject().getPrincipal();

 

5.ehcache缓存权限数据(划重点)

ehcache是专门缓存插件,可以缓存Java对象,提高系统性能。

优点:ehcache是shiro的缓存插件,导入ehcache后在授权时只需要授权一次,而不需要重复授权

1>在pom.xml文件引入ehcache的依赖(导入jar包)

		<!-- 引入ehcache的依赖 -->
		<dependency>
			<groupId>net.sf.ehcache</groupId>
			<artifactId>ehcache-core</artifactId>
			<version>2.6.6</version>
		</dependency>

2>编写ehcache配置文件:ehcache.xml

<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
    <diskStore path="java.io.tmpdir"/>
    <defaultCache
            maxElementsInMemory="10000"
            eternal="false"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            overflowToDisk="true"
            maxElementsOnDisk="10000000"
            diskPersistent="false"
            diskExpiryThreadIntervalSeconds="120"
            memoryStoreEvictionPolicy="LRU"
            />
</ehcache>

3>在spring配置文件中配置缓存管理器对象,并注入给安全管理对象

	<!-- 注册安全管理器对象 -->
	<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
		<property name="realm" ref="bosRealm"/>
		<!-- 注入缓存管理器 -->
		<property name="cacheManager" ref="cacheManager"/>
	</bean>
	
	<!-- 注册缓存管理器 -->
	<bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
		<!-- 注入ehcache的配置文件 -->
		<property name="cacheManagerConfigFile" value="classpath:ehcache.xml"/>
	</bean>

 

 

 

 

猜你喜欢

转载自blog.csdn.net/langao_q/article/details/83378139