权限模块设计 - shiro框架的使用及扩展

       管理后台的权限管理模块搭建中使用了shiro框架。

       shiro的优点是:相对Spring Security较为轻巧,使用起来自由度大,和Spring框架结合的方式也很成熟。缺点是:shiro本身没实现缓存,需要自己定义缓存实现,更新比较慢,有的功能需要自己拓展。

        shiro文档:http://shiro.apache.org/static/1.2.3/apidocs/  

        十分钟入门:http://shiro.apache.org/10-minute-tutorial.html

        以下总结在项目中使用shiro的方法和管理后台项目中对shiro的拓展。

 

一、使用shiro管理权限

        1. 引入shiro需要的包。使用maven的项目中,在pom.xml增加以下依赖:

               <!-- shiro权限管理 -->
		<dependency>
			<groupId>org.apache.shiro</groupId>
			<artifactId>shiro-core</artifactId>
			<version>1.1.0</version>
		</dependency>
		<dependency>
			<groupId>org.apache.shiro</groupId>
			<artifactId>shiro-web</artifactId>
			<version>1.1.0</version>
		</dependency>
		<dependency>
			<groupId>org.apache.shiro</groupId>
			<artifactId>shiro-spring</artifactId>
			<version>1.1.0</version>
		</dependency>
		<!-- shiro权限管理 end -->

       2. 在项目中增加shiro配置。

         在spring配置文件目录下新建spring-shiro.xml。内容如下:

	<!-- Shiro权限管理配置 -->
	<bean id="shiroFilter"
		class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <!-- shiro通过一个filter控制权限-->
		 <property name="securityManager" ref="securityManager" />
 		<property name="loginUrl" value="/login/execute.do" />  <!-- 登陆页 -->
		 <property name="successUrl" value="/index.jsp" />  <!-- 登陆成功之后跳转的页面 -->
 		<property name="unauthorizedUrl" value="/login/execute.do" /> <!-- 用户在请求无权限的资源时,跳转到这个url -->
 		<property name="filters">
		  	<util:map>
				 <entry key="authc">
					  <bean class="org.apache.shiro.web.filter.authc.PassThruAuthenticationFilter" />
 				</entry>
			  </util:map>
		 </property>
		 <property name="filterChainDefinitions"> <!-- 配置访问url资源需要用户拥有什么权限 配置的优先级由上至下-->
			 <value>
				/=anon
				/template/main.jsp=user
				<!-- api用户信息 -->
 				/api/createApiUser**=perms[api:user:create]  <!-- 权限可以用":"分级,如拥有api权限相当于拥有api*权限(父权限涵盖子权限) -->
				/api/updateApiUser**=perms[api:user:update]
 				/api/*User*=perms[api:user:view]
 				/template/apiUserManage/**=perms[api:user:view] 
 				<!-- api接口管理 -->
 				/api/*Interface*=perms[api:user:interface]
 				<!-- api统计数据 -->
 				/api/querySummaryData**=perms[api:data]
 				/template/apiSumData/**=perms[api:data]
				
              			 /api/**=perms[api:*]
                                ...
				
				 /**=anon
			 </value>
		 </property>
	 </bean>
	 <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
		<property name="realm" ref="permissionsRealm" />  <!-- 自定义登陆及获取权限的源 -->
	 </bean>

 	<!-- shiro权限管理配置 end -->
       在web.xml中增加shiro filter的配置:

    <context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>
			classpath*:applicationContext.xml,
			classpath*:spring-*.xml //此处引入了spring-shiro
		</param-value>
    </context-param>
    ...
    <filter>
        <filter-name>shiroFilter</filter-name>
        <filter-class>
            org.springframework.web.filter.DelegatingFilterProxy
        </filter-class>
    </filter>
     
    <filter-mapping>
        <filter-name>shiroFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>


     3.  定义登陆及获取权限的源。

/**
 * 认证实现类
 * 
 * @author kexm
 * 
 */
@Service("permissionsRealm")
public class PermissionsRealm extends AuthorizingRealm {
    @Autowired
    private AccountDao accountDao;

    @Autowired
    private GroupDao groupDao;

    private Account acc;

    private static LogUtil log = LogUtil.getLogger(PermissionsRealm.class);

    /**
     * 用户权限源(shiro调用此方法获取用户权限,至于从何处获取权限项,由我们定义。)
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        log.info("method[doGetAuthorizationInfo] begin.");
        if (acc != null) {
            if(acc.getAdminType() == 2){//超级管理员 始终拥有所有权限
                info.addStringPermission("*");
                return info;
            }
            try {
                List<UserGroup> gList = accountDao.getUserGroups(acc.getLoginName());
                for (UserGroup g: gList) { //获取用户的组
                    log.info("method[doGetAuthorizationInfo] group<" + g.getName() + ">");
                    List<Permission> pList = groupDao.getGroupPerms(g.getId());
                    for (Permission p: pList) { //获取组内权限
                        log.info("method[doGetAuthorizationInfo] perm<" + p.getName() + "," + p.getPermList() + ">");
                        String permList = p.getPermList();
                        if (permList != null && !"".equals(permList)) {
                            String[] perms = p.getPermList().split(",");
                            for (String perm: perms) {//分别放入容器   (权限以字符串形式呈现,如"api:data"等,和spring-shiro.xml中的配置相对应)
                                log.info("method[doGetAuthorizationInfo] add perm<" + perm + ">");
                                info.addStringPermission(perm);
                            }
                        }
                    }
                }
                return info;//将用户权限返回给shiro
            } catch (Exception e) {
                log.error("method[doGetAuthorizationInfo] e.message<" + e.getMessage() + "> e<" + e + ">", e);
            }
        }
        return null;
    }

    /**
     * 用户登录验证源(shiro调用此方法执行认证)
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authtoken) throws AuthenticationException {
        log.info("method[doGetAuthenticationInfo] begin.");
        UsernamePasswordToken token = (UsernamePasswordToken) authtoken;
        SimpleAuthenticationInfo authenticationInfo = null;
        String userName = token.getUsername();
        String password = new String(token.getPassword());
        Login conf = DefaultConfigure.config.getLogin();
        String MD5pwd = MD5Util.generateSignature(conf.getSalt(), password);
        try {
            if (userName != null && !"".equals(userName)) {
                acc = accountDao.login(userName, MD5pwd);
            }
            if (acc != null) {
                doGetAuthorizationInfo(SecurityUtils.getSubject().getPrincipals());
                authenticationInfo = new SimpleAuthenticationInfo(token.getUsername(), token.getPassword(), getName());
                return authenticationInfo;
            }
        } catch (Exception e) {
            log.error("method[doGetAuthenticationInfo] acc<" + acc + "> message<" + e.getMessage() + "> e<" + e + ">",
                e);
        }
        return null;
    }

}

      3.  shiro中,使用subject管理用户。可以把subject理解为shiro存储用户信息的容器和操纵用户的工具。有了前几步的配置,便可以使用以下代码登入登出,并享受shiro的url权限控制了。

        //登入
        UsernamePasswordToken token = new UsernamePasswordToken(loginName, password);
        Subject user = SecurityUtils.getSubject();
        user.login(token);
        //使用shiro自带的session存储用户信息 独立于httpSession
        Session ss = user.getSession().setAttribute("userInfo", acc);
        //登出
        SecurityUtils.getSubject().logout();

      4. 在页面中使用shiro标签。假如我们要让有权限的用户看到某些菜单或按钮,可以用以下方式。

<%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>
<shiro:hasPermission name="api:data">
        who has permission can see
</shiro:hasPermission>

         

      以上只使用了shiro的permission管理,shiro还支持对role的管理,如有进一步抽象的需求可以使用。


二、分布式环境,让shiro与redis结合

        假如我们的web项目是分布式部署的,则需要让shiro把session和用户权限到放到集中缓存上去。Shiro本身不实现Cache,但是提供了接口,方便更换不同的底层Cache实现。

shiro提供的cache接口:


    public interface Cache<K, V> {  
        //根据Key获取缓存中的值  
        public V get(K key) throws CacheException;  
        //往缓存中放入key-value,返回缓存中之前的值  
        public V put(K key, V value) throws CacheException;   
        //移除缓存中key对应的值,返回该值  
        public V remove(K key) throws CacheException;  
        //清空整个缓存  
        public void clear() throws CacheException;  
        //返回缓存大小  
        public int size();  
        //获取缓存中所有的key  
        public Set<K> keys();  
        //获取缓存中所有的value  
        public Collection<V> values();  
    }  

    观察接口可以发现,我们需要实现一个keys方法。这个方法限制了shiro不能使用缓存集群(SharedRedis不提供这个方法,只有单台redis可用keys方法,望找到解决方案)。


    我们的项目使用redis作为集中缓存,shiro和redis结合的方式可以使用一个现成的工具——shiro-redis。

    shiro-redis的github:https://github.com/alexxiyang/shiro-redis

    目前管理后台项目正在使用此工具。这个工具有一处问题:读取缓存时没对读取的对象延长有效期,修复这个BUG之后还挺好用。


三、对shiro页面标签拓展,增加and or not 逻辑符

    参考:http://jinnianshilongnian.iteye.com/blog/1864800

     使用过shiro的朋友应该都知道在要想实现any permission的验证是比较麻烦。

     很多朋友刚开始接触时以为如<shiro:hasPermission name="showcase:tree:*"> 代表验证用户是否拥有tree下的任何权限,但这是错误的。如果我们把showcase:tree:*授权给用户,那么此时表示用户具有showcase:tree资源的任意权限,如<shiro:hasPermission name="showcase:tree:*">或shiro:hasPermission name="showcase:tree:create">都能验证成功。

     还有朋友认为<shiro:hasPermission name="showcase:tree:create,update"> 是或的关系,也不是,默认是且的关系。

     下载了最新的shiro1.3.0-SNAPSHOT 发现并没有增加新的标签或其他支持。

    因此我们需要简单的扩展下shiro来支持像spring security 3那样的@Secured支持表达式的强大注解。
我们扩展AuthorizingRealm,并修改:

    private static final String OR_OPERATOR = " or ";
    private static final String AND_OPERATOR = " and ";
    private static final String NOT_OPERATOR = "not ";
    /**
     * 支持or and not 关键词  不支持and or混用
     * @param principals
     * @param permission
     * @return
     */
    public boolean isPermitted(PrincipalCollection principals, String permission) {
        if(permission.contains(OR_OPERATOR)) {
            String[] permissions = permission.split(OR_OPERATOR);
            for(String orPermission : permissions) {
                if(isPermittedWithNotOperator(principals, orPermission)) {
                    return true;
                }
            }
            return false;
        } else if(permission.contains(AND_OPERATOR)) {
            String[] permissions = permission.split(AND_OPERATOR);
            for(String orPermission : permissions) {
                if(!isPermittedWithNotOperator(principals, orPermission)) {
                    return false;
                }
            }
            return true;
        } else {
            return isPermittedWithNotOperator(principals, permission);
        }
    }

    private boolean isPermittedWithNotOperator(PrincipalCollection principals, String permission) {
        if(permission.startsWith(NOT_OPERATOR)) {
            return !super.isPermitted(principals, permission.substring(NOT_OPERATOR.length()));
        } else {
            return super.isPermitted(principals, permission);
        }
    }

     如上代码即可以实现简单的NOT、AND、OR支持,不过缺点是不支持复杂的如AND、OR组合。

     如下标签在拓展后可以生效:

<shiro:hasPermission name="api:data or api:user"></shiro:hasPermission>
<pre name="code" class="html"><shiro:hasPermission name="api:data and api:user"></shiro:hasPermission> 
<shiro:hasPermission name="not api:data"></shiro:hasPermission>


 

         

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
JeeSpringCloud是一个基于SpringBoot2.0的后台权限管理系统,界面简洁美观敏捷开发系统架构。核心技术采用Spring、MyBatis、Shiro没有任何其它重度依赖。 互联网云快速开发框架,微服务分布式代码生成的敏捷开发系统架构。项目代码简洁,注释丰富,上手容易,还同时集中分布式、微服务,同时包含许多基础模块和监控、服务模块模块包括:定时任务调度、服务器监控、平台监控、平台设置、开发平台、单点登录、Redis分布式高速缓存、会员、营销、在线用户、日志、在线人数、访问次数、调用次数、直接集群、接口文档、生成模块、代码实例、安装视频、教程文档 代码生成(单表、主附表、树表、列表和表单、redis高速缓存对接代码、图表统计、地图统计、vue.js)、dubbo、springCloud、SpringBoot、mybatis、spring、springmvc。 功能 用户管理:用户是系统操作者,该功能主要完成系统用户配置。 部门管理:配置系统组织机构(公司、部门、小组),树结构展现支持数据权限。 岗位管理:配置系统用户所属担任职务。 菜单管理:配置系统菜单,操作权限,按钮权限标识等。 角色管理:角色菜单权限分配、设置角色按机构进行数据范围权限划分。 字典管理:对系统中经常使用的一些较为固定的数据进行维护。 参数管理:对系统动态配置常用参数。 通知公告:系统通知公告信息发布维护。 操作日志:系统正常操作日志记录和查询;系统异常信息日志记录和查询。 登录日志:系统登录日志记录查询包含登录异常。 在线用户:当前系统中活跃用户状态监控。 定时任务:在线(添加、修改、删除)任务调度包含执行结果日志。 代码生成:前后端代码生成(单表、主附表、树表、列表和表单、增删改查云接口、redis高速缓存对接代码、图表统计、地图统计、vue.js) ,并生成菜单和权限直接使用。 系统接口:根据业务代码自动生成相关的api接口文档。 连接池监视:监视当期系统数据库连接池状态,可进行分析SQL找出系统性能瓶颈。 在线接口文档:使用swager生成在线文档。 ActiveMQ队列:提供ActiveMQ队列,处理批量发送大数据量邮件、大数据量日志文件。 工作流:功能包括在线办公、我的任务、审批测试、流程管理、模型管理。 CMS:功能包括内容管理、内容管理、统计分析、栏目设置、首页。 dubbo:代码生成直接生成dubbo对接代码。 服务器Down机邮件监控:通过定时任务监控服务器是否Down机,并发送通知邮件。 服务器监控:通过sigar进行服务器图形化监控。 异常邮件监控:全局拦截系统异常,并发送通知邮件。 单点登录:使用shior和Redis、共享session方式实现单点登录。 Redis分布式高速缓存:代码生成直接生成Redis对接代码。 特性: JeeSpringCloud基于SpringBoot+SpringMVC+Mybatis+Redis+SpringCloud+Vue.js微服务分布式代码生成的敏捷开发系统架构。项目代码简洁,注释丰富,上手容易,还同时集中分布式、微服务,同时包含许多基础模块(用户管理,角色管理,部门管理,字典管理等10个模块。成为大众认同、大众参与、成就大众、大众分享的开发平台。JeeSpring官方qq群(328910546)。代码生成前端界面、底层代码(spring mvc、mybatis、Spring boot、Spring Cloud、微服务的生成)、安全框架、视图框架、服务端验证、任务调度、持久层框架、数据库连接池、缓存框架、日志管理、IM等核心技术。努力用心为大中小型企业打造全方位J2EE企业级平台ORM/Redis/Service仓库开发解决方案。一个RepositoryService仓库就直接实现dubbo、微服务、基础服务器对接接口和实现。 努力用心为大中小型企业打造全方位J2EE企业级平台开发解决方案。 Spring Boot/Spring cloud微服务是利用云平台开发企业应用程序的最新技术,它是小型、轻量和过程驱动的组件。微服务适合设计扩展、易于维护的应用程序。它可以使开发更容易,还能使资源得到最佳利用。 微服务/集群(nignx) 支持REST风格远程调用(HTTP + JSON/XML):基于非常成熟的Spring Boot框架,在Spring Boot Spring Cloud中实现了REST风格(HTTP + JSON/XML)的远程调用,以显著简化企业内部的跨语言交互,同时显著简化企业对外的Open API、无线API甚至AJAX服务端等等的开发。 事实上,这个REST调用也使得Dubbo可以对当今特别流行的“微服务”架构提供基础性支持。 另外,REST调用也达到了比较高
JavaWeb是基于 SpringBoot2+Layui2.5.6+Thymeleaf++Shiro+MybatisPlus 研发的权限(RBAC)及内容管理系统,致力于做更简洁的后台管理框架,包含系统管理、代码生成、权限管理、站点、广告、布局、字段、配置等一系列常用的模块,整套系统一键生成所有模块(包括前端UI),一键实现CRUD,简化了传统手动抒写重复性代码的工作。 同时,框架提供长大量常规组件,如上传单图、上传多图、上传文件、下拉选择、复选框按钮、单选按钮,城市选择、富文本编辑器、权限颗粒度控制等高频使用的组件,代码简介,使用方便,节省了大量重复性的劳动,降低了开发成本,提高了整体开发效率,整体开发效率提交80%以上,JavaWeb框架专注于为中小企业提供最佳的行业基础后台框架解决方案,执行效率、扩展性、稳定性值得信赖,操作体验流畅,使用非常优化,欢迎大家使用及进行二次开发。 JavaWeb介绍: 1、模块化:全新的架构和模块化的开发机制,便于灵活扩展和二次开发。 2、模型/栏目/分类信息体系:通过栏目和模型绑定,以及不同的模型类型,不同栏目可以实现差异化的功能,轻松实现诸如资讯、下载、讨论和图片等功能。通过分类信息和栏目绑定,可以自动建立索引表,轻松实现复杂的信息检索。 3、JavaWeb企业级开发框架是一套基于SpringBoot2 + Layui开发出来的框架。 4、支持SQLServer、MySQL、Oracle、PostgreSQL、SQLite等多数据库类型。模块设计,层次结构清晰。 5、Shiro权限认证,操作权限控制精密细致,对所有管理链接都进行权限验证,可控制到导航菜单、功能按钮。提高开发效率及质量。 6、常用类封装,日志、缓存、验证、字典、文件(本地、七牛云)。等等,目前兼容浏览器(Chrome、Firefox、360浏览器等) 7、适用范围:可以开发OA、ERP、BPM、CRM、WMS、TMS、MIS、BI、电商平台后台、物流管理系统、快递管理系统、教务管理系统等各类管理软件。 JavaWeb功能特性: 严谨规范: 提供一套有利于团队协作的结构设计、编码、数据等规范。 高效灵活: 清晰的分层设计、钩子行为扩展机制,解耦设计更能灵活应对需求变更。 严谨安全: 清晰的系统执行流程,严谨的异常检测和安全机制,详细的日志统计,为系统保驾护航。 组件化: 完善的组件化设计,丰富的表单组件,让开发列表和表单更得心应手。无需前端开发,省时省力。 简单上手快: 结构清晰、代码规范、在开发快速的同时还兼顾性能的极致追求。 自身特色: 权限管理、组件丰富、第三方应用多、分层解耦化设计和先进的设计思想。 高级进阶: 分布式、负载均衡、集群、Redis、分库分表。 命令行: 命令行功能,一键管理应用扩展。 基于SpringBoot 简化了大量项目配置和maven依赖,让您更专注于业务开发,独特的分包方式,代码多而不乱。 利用Thymeleaf模板引擎 对前台页面进行封装和拆分,使臃肿的html代码变得简洁,更加易维护。 JS封装 对常用js插件进行二次封装,使js代码变得简洁,更加易维护。 参数配置 灵活控制常用功能的开关,无需重启项目即可生效,实时刷新。 演示地址账号密码: 登录账号:admin 登录密码:123456 验证码:520
kvf-admin是一套基于springboot、mybatis、shiro及layui的轻量级快速开发框架、脚手架、后台管理系统、权限系统、基于activiti6整合的工作流OA系统,上手简单,拿来即用。.zip 当然可以,以下是一份关于您的Java SpringBoot项目的简介描述: 探索Java的SpringBoot魔法 亲爱的开发者们,准备好一起踏上这次深入Java的SpringBoot之旅了吗?如果您正在寻找一个现代化、高效且易于扩展的开发框架,那么这个SpringBoot项目将是您的理想选择。 主要特点: 快速开发:SpringBoot通过自动配置和约定大于配置的原则,大大简化了项目设置和开发过程。 易于扩展:SpringBoot与生俱来的灵活性使您可以轻松集成各种服务和数据库,以满足您日益增长的需求。 安全性:内置的安全特性,如OAuth2和Spring Security,确保您的应用程序安全无虞。 微服务支持:SpringBoot是微服务架构的理想选择,可以帮助您构建模块化、可扩展的应用程序。 社区支持:全球的开发者社区意味着您可以在遇到问题时找到大量的资源和支持。 无论您是初出茅庐的Java新手,还是经验丰富的开发者,这个项目都将为您提供一个深入了解SpringBoot的机会。无论您是想学习新的技能,还是想提高现有应用程序的性能,这个项目都将是您的宝贵资源。 内容概览 项目设置和初始化 控制器设计和实现 数据持久化与数据库集成 安全性和身份验证 性能优化和监控 部署和生产环境考虑 现在,是时候让您的Java技能得到充分发挥,并掌握SpringBoot的魔法了!这个项目将带领您从基础到高级,探索SpringBoot的每一个角落。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值