使用Shiro 集合Spring来实现权限控制

Posted ReiNer_Shir2

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用Shiro 集合Spring来实现权限控制相关的知识,希望对你有一定的参考价值。

这只是笔记 


web.xml中引入 spring-shiro.xml

spring-shiro.xml :

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xmlns:context="http://www.springframework.org/schema/context"  
	xmlns:util="http://www.springframework.org/schema/util"
	xsi:schemaLocation="http://www.springframework.org/schema/beans 
	http://www.springframework.org/schema/beans/spring-beans-3.0.xsd   
    http://www.springframework.org/schema/util 
    http://www.springframework.org/schema/util/spring-util-3.0.xsd">
    
	<description>Shiro 配置</description>
	
	<!--	权限配置对照表
* @see   /admin=authc,roles[admin]      表示用户必需已通过认证,并拥有admin角色才可以正常发起'/admin'请求
数据库权限格式admin:list
* @see   /edit=authc,perms[admin:edit]  表示用户必需已通过认证,并拥有admin:edit权限才可以正常发起'/edit'请求
* @see   /home=user                     表示用户不一定需要已经通过认证,只需要曾经被Shiro记住过登录状态就可以正常发起'/home'请求
* @see   /admins/**=anon             无参,表示可匿名使用,可以理解为匿名用户或游客
* @see   /admins/user/**=authc       无参,表示需认证才能使用
* @see   /admins/user/**=authcBasic  无参,表示httpBasic认证
* @see   /admins/user/**=user        无参,表示必须存在用户,当登入操作时不做检查
* @see   /admins/user/**=ssl         无参,表示安全的URL请求,协议为https
* @see   /admins/user/**=perms[user:add:*]
* @see       参数可写多个,多参时必须加上引号,且参数之间用逗号分割,如/admins/user/**=perms["user:add:*,user:modify:*"]
* @see       当有多个参数时必须每个参数都通过才算通过,相当于isPermitedAll()方法
* @see   /admins/user/**=port[8081]
* @see       当请求的URL端口不是8081时,跳转到schemal://serverName:8081?queryString
* @see       其中schmal是协议http或https等,serverName是你访问的Host,8081是Port端口,queryString是你访问的URL里的?后面的参数
* @see   /admins/user/**=rest[user]
* @see       根据请求的方法,相当于/admins/user/**=perms[user:method],其中method为post,get,delete等
* @see   /admins/user/**=roles[admin] 参数可写多个,多个时必须加上引号,且参数之间用逗号分割,如/admins/user/**=roles["admin,guest"]
* @see       当有多个参数时必须每个参数都通过才算通过,相当于hasAllRoles()方法  -->
	<!-- 权限配置 -->
	<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
		<property name="securityManager" ref="securityManager" />
		<property name="loginUrl" value="/direct.html" />
		<property name="successUrl" value="/index.html" />
		<property name="unauthorizedUrl" value="/403.html" /> <!-- 无权限跳转页面 -->
   		<property name="filters">  
            <util:map>  
                <entry key="authc">  
                    <bean class="org.apache.shiro.web.filter.authc.PassThruAuthenticationFilter"/> 
                    <!-- <bean class="com.hbs.dipper.interceptor.MethodAuthenticationFilter"/>  -->
                </entry>  
            </util:map>  
        </property> 
		<property name="filterChainDefinitions">
			<value>
			    <!-- 静态文件控制 -->
				/css/** = anon
				/images/** = anon
				/js/** = anon
				/index.html = user
				/direct.html = anon
				/403.html = anon
				/login.html = anon
				
				<!-- 用户管理权限 -->
				/user/logout = anon  <!-- 无需控制 -->
				/user/getCurrentUser = user <!-- 登陆即不做检查 -->
				/user/updatePwd = user
				/user/login/** = anon
				/user/get*/** = perms[user:view] <!-- 查看权限 -->
				/view/user/** = perms[user:view] <!-- html权限控制 -->
				/user/add*/** = perms[user:add] <!-- 添加权限 -->
				/user/delete*/** = perms[user:delete] <!-- 删除权限 -->
				/user/update*/** = perms[user:update] <!-- 修改权限 -->
				/user/changeStatus/** = perms[user:enableOrDisable] <!-- 启用禁用用户 -->
				/user/resetPassword/** = perms[user:resetPwd] <!-- 重制密码 -->
				
				<!-- 部门权限  -->
				/company/get*/** = perms[company:view] <!-- 查看权限 -->
				/view/company/** = perms[company:view] <!-- html权限控制 -->
				/company/add*/** = perms[company:add] <!-- 添加权限 -->
				/company/delete*/** = perms[company:delete] <!-- 删除权限 -->
				/company/update*/** = perms[company:update] <!-- 修改权限 -->
				
				<!-- 角色权限  -->
				/role/get*/** = perms[role:view] <!-- 查看权限 -->
				/view/role/** = perms[role:view] <!-- html权限控制 -->
				/role/add*/** = perms[role:add] <!-- 添加权限 -->
				/role/delete*/** = perms[role:delete] <!-- 删除权限 -->
				/role/update*/** = perms[role:update] <!-- 修改权限 -->
				
				<!-- 权限管理  -->
				/permission/get*/** = perms[permission:view] <!-- 查看权限 -->
				/view/permission/** = perms[permission:view] <!-- html权限控制 -->
				/permission/add*/** = perms[permission:add] <!-- 添加权限 -->
				/permission/delete*/** = perms[permission:delete] <!-- 删除权限 -->
				/permission/update*/** = perms[permission:update] <!-- 修改权限 -->
				
				
				/**=rest[authc]<!-- 拦截所有get、post请求 -->
			</value>
			<!-- /**=rest[authc]  验证所有后台如get、post请求 -->
		</property>
		
	</bean>

  <bean id="logout" class="org.apache.shiro.web.filter.authc.LogoutFilter">
        <property name="redirectUrl" value="/login" />
  </bean>
    
  <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
	    <property name="realm" ref="monitorRealm" />
	    <!-- 需要使用cache的话加上这句
	    <property name="cacheManager" ref="shiroEhcacheManager" />
	     -->
  </bean>
  
  <!-- depends-on 表示在实例化该对象之前先实例化 depends-on中的对象 -->
  <bean id="monitorRealm" class="com.hbs.dipper.interceptor.MonitorRealm" />
	  
  <!-- 启用spring注解方式拦截shiro权限 -->
  <bean
    class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
    <property name="securityManager" ref="securityManager" />
  </bean>
  
  <!-- 自定义角色过滤器 支持多个角色可以访问同一个资源 eg:/home.jsp = authc,roleOR[admin,user]  用户有admin或者user角色 就可以访问-->  
  <!-- <bean id="roleOR" class="com.yale.app.security.OneRoleAuthorizationFilter"/> -->
  
   <!-- srping注解配置 Post processor that automatically invokes init() and destroy() methods -->  
    <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>  
<!-- 启用shiro为spring配置的bean注释,只运行在lifecycleBeanProcessor之后  -->
    <bean id="annotationProxy" class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" 
    depends-on="lifecycleBeanPostProcessor">
		<property name="proxyTargetClass" value="true" />
    </bean>

   
     <!-- 用户授权信息Cache, 采用EhCache,需要的话就配置上此信息 
  <bean id="shiroEhcacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
    <property name="cacheManagerConfigFile" value="classpath:ehcache-shiro.xml" />
  </bean>
  -->
  
  
  	<!-- spring对ehcache的缓存工厂支持 -->
	<!-- <bean id="ehCacheManagerFactory"
		class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
		<property name="configLocation" value="classpath:ehcache.xml" />
	</bean> -->
	
</beans>


shiro加载权限具体实现类 

package com.hbs.dipper.interceptor;

import java.util.List;

import javax.annotation.Resource;

import org.apache.log4j.Logger;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Component;

import com.hbs.dipper.system.model.Permission;
import com.hbs.dipper.system.model.Role;
import com.hbs.dipper.system.model.User;
import com.hbs.dipper.system.service.PermissionService;
import com.hbs.dipper.system.service.RoleService;
import com.hbs.dipper.system.service.UserService;
import com.hbs.dipper.util.SpringContextUtil;
@Component
public class MonitorRealm extends AuthorizingRealm {

	//由于shiro是在其他service之前加载,所以必须在运行时加载
	UserService userService;
	RoleService roleService;
	PermissionService permissionService;
	private Logger logger = Logger.getLogger(MonitorRealm.class);

	/**
     * 授权查询回调函数, 进行鉴权但缓存中无用户的授权信息时调用.
     * 将权限查出来
     */
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo( PrincipalCollection principals) {
		logger.debug("get permissions================================>");
		Subject currentUser =SecurityUtils.getSubject();
		Session session = currentUser.getSession();
        User user = (User) session.getAttribute("user");
		 if( user != null ) {
           SimpleAuthorizationInfo info = (SimpleAuthorizationInfo) session.getAttribute("info");
           if(info==null){
        	   info = new SimpleAuthorizationInfo();
	           if(user.getUserId().equals(1)){//超级管理员,查出所有权限
	        	   info.addRole("admin");
	        	   List<Permission> permissions = permissionService.getList(null);
	        	   addPermission(info,permissions);
	           }else{//从数据库查出权限并添加
		           List<Role> roles = roleService.getRoleByUser(user.getUserId());
		           for (Role role : roles) {
		        	   info.addRole(role.getRoleName()); 
		        	   List<Permission> permissions = permissionService.getPermissionByRole(role.getRoleId());
		        	   for (Permission permission : permissions) {
		         		   info.addStringPermission(permission.getPermissionCode());
		        	   }
		           }
	           }
	           session.setAttribute("info", info);//缓存到session中
           }
           return info;  
        } else {  
        	throw new AuthorizationException("login user is null!");  
        }  
	}
	
	/**
	* @Title: addPermission 
	* @Description: TODO(迭代添加权限) 
	* @param @param info
	* @param @param list    参数 
	* @return void    返回类型 
	* @throws
	 */
	public void addPermission(SimpleAuthorizationInfo info,List<Permission> list){
		for (Permission permission : list) {
 		   info.addStringPermission(permission.getPermissionCode());
 		   if(permission.getChildren()!=null&&permission.getChildren().size()>0)
 			  addPermission(info,permission.getChildren());
 	   }
	}

	
	/**
     * 认证回调函数,登录时调用.
     * 经测试登陆时会调用两次。。。
     */
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(
			AuthenticationToken authcToken) throws AuthenticationException {
		bind();
		logger.debug("login=================================>");
		UsernamePasswordToken token = (UsernamePasswordToken) authcToken;  
        String  password = String.valueOf(token.getPassword());  
        //调用操作数据库的方法查询user信息  
        User user = userService.getByLoginName(token.getUsername()) ;
        if( user != null ) {  
            if(password.equals(user.getPassword())){  
            	return new SimpleAuthenticationInfo(user.getUserId(), user.getPassword(), getName());  
            }else{  
                return null;  
            }  
        } else {  
            return null;  
        }  
	}
	
	
	private void bind(){
		if(userService==null)
			userService = (UserService) SpringContextUtil.getBean("userService");
		if(roleService==null)
			roleService = (RoleService) SpringContextUtil.getBean("roleService");
		if(permissionService==null)
			permissionService = (PermissionService) SpringContextUtil.getBean("permissionService");
	}

	public void clearCachedAuthorizationInfo(String principal) {
		SimplePrincipalCollection principals =
			new SimplePrincipalCollection(principal, getName());
		clearCachedAuthorizationInfo(principals);
	}
}

尚未解决的问题: 无法在shiro的Realm中使用注解 ,报空异常,初步判断是在spring加载其他bean之前执行了


以上是关于使用Shiro 集合Spring来实现权限控制的主要内容,如果未能解决你的问题,请参考以下文章

Spring Boot + Spring Cloud 实现权限管理系统 后端篇(二十四):权限控制(Shiro 注解)

Spring Boot + Vue + Shiro 实现前后端分离权限控制

Spring Boot 整合 Shiro 实现登录认证与权限控制

自己动手实现简单权限控制

Spring Security实现登录认证和权限控制

Spring Boot + Shiro 实现前后端分离权限控制