1.介绍今天给大家推荐一款非常简单实用的开源权限框架:Shiro,也是Java官方推荐的权限框架。网上虽然有很多类似的文章,但都不是很完善,尤其是freemaker、springboot、shiro、redis集成相关的文章很少,而且比较理论化,缺乏完整的可运行的源码。本文提供的源码,您可以直接将代码复制到自己的项目中使用,参数可配置,并提供完整的文档。源码实现的功能:提供可视化后台界面;在管理员后台添加用户、系统功能和角色,关联系统功能和角色,分配用户角色;登录/身份认证;权限验证;session管理(redis实现分布式集群管理);缓存(redis实现分布式集群管理);登录失败限制(redis实现分布式集群管理);2.Shiro介绍首先让我们先来了解一下Shiro是什么?Shiro是一个功能强大且易于使用的Java安全框架,主要用于身份验证、授权、加密和会话管理。与功能相似的SpringSecurity相比,Shiro要简单很多,满足大部分企业级系统应用。Shiro的具体功能是什么?下面是一些简单的例子:登录/认证;验证权限,即验证一个人是否有权限做某事;Session管理,管理用户特定的session(支持分布式session管理),支持web、non-web、ejb;加密确保数据安全;Caching:缓存(支持分布式缓存管理);登录失败限制;记住我:记住登录状态,登录一次,下次无需重新登录;RunAs:允许一个用户冒充另一个用户(如果他们允许)访问;Shiro可以和Spring友好集成,支持jsp标签(官方不支持freemaker标签,本文源码实现了一套freemaker标签);三、Shiro详解本节重点介绍Shiro的架构和一些相关术语。通过鉴权和权限控制流程的讲解,读者可以基本掌握shiro的运行原理。1.系统架构Shiro有三个关键概念:SubjectSecurityManagerRealms三者的关系如下图所示:Subject:本质上是对当前访问用户的抽象描述。Shiro主要提供了一系列以Subject为核心的API,围绕Subject设计各种用户认证和权限控制接口。但是所有的Subject都需要SecurityManager。当你与Subject交互时,这些交互实际上会转化为与SecurityManager的交互。SecurityManager:Shiro架构的核心组件,通过它可以协同其他组件完成用户的认证和授权。SecurityManager是Shiro框架的控制器,它执行与安全相关的操作并管理应用程序所有用户的状态。这些操作和状态包括:用户认证;权限控制;会话管理;缓存管理;Realm的协调调度;事件传播;“记住我”服务;创建主题;登出;不同的数据源,例如:LDAP、关系数据库、配置文件等。当它需要与安全数据交互时,例如用户帐户或访问控制,Shiro从一个或多个Realms中寻找。Shiro提供了一些可以直接使用的Realms。如果默认的Realms不能满足需求,也可以自定义Realms(本文自定义Realms,数据源为mysql,提供完整的数据库表结构和demo数据)。2.系统详细架构Authenticator(用户认证管理器)该组件主要用于处理用户登录逻辑。它通过调用Realm的接口来判断当前登录用户的身份。AuthenticationStrategy(用户认证策略)如果系统配置了多个Realms,则需要使用AuthenticationStrategy来协调这些Realms,以判断用户的登录认证是否成功。(比如一个Realm验证成功,其他都验证失败,是验证成功了?还是说所有Realm都验证成功了?还是第一个成功才算成功?可见,策略还是挺复杂的)。Authorizer(授权管理器)该组件主要用于用户权限控制。通俗地说,就是确定用户能做什么,不能做什么。SessionManager(会话管理器)SessionManager知道如何创建会话,管理用户会话的生命周期,并为用户在所有运行环境中提供健壮的会话管理体验。SessionDAO允许用户使用任何类型的数据源来存储Session数据。SessionDAO(org.apache.shiro.session.mgt.eis.SessionDAO)用于替代SessionManager来进行Session相关的增删改查。该接口允许我们将任何一种数据存储方法引入到会话管理的基本框架中。(本文源码实现了redisDao,使用redis实现了session的统一管理,同时源码还提供了内存管理session,可以通过配置方便的切换使用。)Cache缓存鉴权,授权和会话数据,以提高应用程序性能。由于Cache不是安全框架的核心功能,shiro本身并没有完整实现Cache机制。Cache接口相当于底层缓存框架的顶层接口。Shiro所有的缓存操作都是通过这个Cache顶层接口来操作的,底层实现可以是任意的Cache实例(JAche、Ehcache、RedisCache、OSCache、JBossCache..)(本文源码实现了Ehcache、RedisCache和内存Cache。三者可以通过配置方便的切换使用。)CacheManager(org.apache.shiro.cache.CacheManager)缓存管理器。创建和管理缓存,为认证、授权和会话管理提供缓存数据,避免直接访问数据库,提高效率。cacheManager维护Cache实例的生命周期。和Cache一样,只是Shiro缓存框架的顶层接口,具体的底层实现可以随意。(本文源码实现RedisCacheManager,利用redis实现缓存的统一管理。同时源码还提供了内存和ehcache管理缓存,可以通过配置方便的切换使用。)3.其他基本概念的解释分布式会话管理将会话保存到独立的缓存服务器中,保证在服务重启或nginx做负载均衡时,用户会话可见。(本文提供的源码使用redis保存session会话)freemakertags通过使用tags,可以非常方便的实现前后端数据通信。Shiro默认支持jsp标签,不支持freemaker标签。为了满足前端使用freemaker的系统使用shiro的要求,定制了一套freemakershiro标签,并提供源码。4.Shiro实战案例分享本部分分为三个部分。数据库表介绍了权限管理系统的源代码结构。认证授权过程分析数据库表权限管理系统源码结构。项目一、demo-shiro-interface项目扩展如下:该子项目主要功能是提供与用户、角色、功能、权限、分页相关的接口类和实体。2、demo-shiro-service项目扩展如下:该子项目主要功能是实现demo-shiro-interface中的接口类,实现业务逻辑编码。3、demo-shiro-web工程扩展如下:其中UserController.java具有用户登录认证、注销管理、用户添加、用户审计等功能。SysController.java系统功能模块管理。*tag.java为freemaker定制的Shiro标签,是本项目的关键部分。CustomShiroSessionDAO.java自定义session管理,本项目提供依赖redis集中session管理的功能,是本项目的关键部分。RedisCacheManager.java自定义Cache管理,本项目提供了依赖于redis集中Cache管理的功能,是本项目的关键部分。MyShiroRealm.java自定义realm,用户认证和授权需要用到该类提供的功能,是本项目的关键部分。FreemarkerConfiguration.javaShiroTagFreeMarkerConfigurer.java自定义freemakershiro标签注入实现。4、springboot-shiro-configure项目展开如下:其中*Properties.java读取application.yml配置文件中对应的配置参数,如session过期时间,最大连续登录失败次数等。RetryLimitHashedCredentialsMatcher.java管理连续登录失败的最大次数和时间间隔。当达到最大登录失败次数时,系统提示用户N分钟内不能重试。ShiroAutoConfiguration.javaShiroConfiguration.javaShiro允许用户自定义Realms、CacheManager和SessionManager。这两个类文件的作用是实现自定义类的依赖管理。这两个类也是Shiro与springboot集成的关键部分。这里的源码实现涉及springboot@ConditionalOnxxx的相关注解技术,建议读者学习相关技术点。以上源码文件中都有非常完整的注释,有兴趣的同学可以阅读。认证&授权流程分析Shiro的所有功能都围绕着两个核心功能展开,即用户登录认证和用户访问授权。本项目除了这两个核心功能外,还自定义了cacheManager、sessionManager,使用各种方法进行缓存和session的管理。本节将对以上四个问题进行分析。1、用户登录认证Shiro用户认证时序图通过调用Subject.login(token)方法启动用户认证流程。执行currentUser.login(token)后,SecurityManager会收到AuthenticationToken并将其发送到配置的Realm进行必要的认证。所以这一步调用login(token)方法的时候,会去到MyRealm.doGetAuthenticationInfo()方法。具体验证方法如下:MyShiroRealm.doGetAuthenticationInfo()。UserRealm继承AuthorizingRealm,在其父类AuthenticatingRealm的getAuthenticationInfo方法中调用credentialsMatcher的doCredentialsMatch来验证用户输入的用户名和密码是否匹配。使用HashedCredentialsMatcher进行加密。加密方式为customsalt(本项目使用www),哈希数为1024,Base64解码,加密算法为md5。当注册对应的配置文件applications.yml后,密码明晚改成密??文。具体代码实现如下:其中,Constants.initPassword为添加用户时的默认密码:111111。用户注销时,Shiro用户必须执行logout(),Session信息必须注销,以免影响下一步用户认证授权SecurityUtils.getSubject().logout();req.getSession().invalidate();2.用户访问授权shiro访问授权时序图用户认证通过后,进入后台管理系统。后台系统使用freemaker搭建,所有菜单都在sidebar.flt模板文件中管理。freemaker的shiro标签配置如下:redbordername="4"orname="4-1"其中4和4-1代表下图红框内role.getPermissionsName()的值。permissionsName的值来自后台添加该功能时为菜单设置的值。如下图所示:3.session管理系统提供了两种session管理方式ehcache管理Redis集中管理配置:ShiroConfiguration.java当该方法被注释掉时,Shiro的session会话默认由ehcache管理。开启该方法后,shiro的session会话由redis管理。4、缓存管理系统提供了三种session管理方式本地内存管理ehcache管理Redis集中管理Configuration:ShiroConfiguration.java想用哪个方式,把另外两个方式注释掉。(有兴趣的同学可以自己开发一个新的功能,通过配置参数启用某种会话管理方式)五、系统配置本节分为两部分。Shiro管理配置主要涉及两个配置文件application.yml和ehcache.xml,下面将对各个配置参数进行详细介绍。后台系统权限配置使用后台管理系统页面添加用户、系统功能、角色、权限、用户权限分配。1.Shiro管理配置application.ymlrealm类自定义realm(com.xinwei.shiro.MyShiroRealm),完成认证授权。custom-authc-filter-class:自定义过滤器com.xinwei.shiro.AjaxAuthorizationFilter。login-url是登录url。当session超时继续访问系统时,会自动跳转到这个url。success-url认证通过后,系统进入url功能界面。retry-max用户登录认证,允许的最大连续失败次数。retry-expire-time-redis用户登录认证,达到最大连续失败次数后,需要等待重新进入的时间间隔(单位:秒)。(该参数仅在使用redis管理缓存时生效。如果使用ehcache管理缓存,需要参考ehcache.xml。)authorization-expire-time-redis用户授权校验的缓存过期时间,在过期时间内,使用需要授权的菜单时,不需要重复执行,提高了系统的访问效率。(该参数只有在使用redis管理session时才生效,如果使用ehcache管理缓存,需要参考ehcache.xml。)hash-iterations加密密码时,要做的hash次数,本例中,1024个哈希值。hash-algorithm-name密码加密使用的加密方式,本例使用MD5。stored-credentials-hex-encoded默认值为true,默认使用Hex解码,false时,使用Base64解码。global-session-timeout会话存活时间(注意,单位是毫秒,0表示立即过期,-1表示永不过期)。validation-interval检查会话是否过期的时间间隔。validation-scheduler-enabledtrue,扫描会话线程,负责清理超时会话。filter-chain-definitions:/media/**:anon访问此目录中的文件而无需权限验证。/admin/**:authc设置拦截器,访问该目录下的文件需要权限验证。ehcache.xml的具体含义可以参考https://www.cnblogs.com/sdream/p/5966668.html。2、后台系统权限配置添加用户注意:新添加的后台用户,默认密码为:111111,审核通过后方可登录系统。为用户添加角色添加系统功能:功能码必须唯一,需要在freemaker中使用。添加角色给角色赋予权限6.其他Shiro是一个功能齐全的框架,用起来很简单,但是要用好却相当困难。欢迎大家多多练习,有问题一起讨论。项目源码地址:https://github.com/wzjgn/shiro-freemaker-springboot-redis-mysql.git参考:https://www.cnblogs.com/learnhow/p/5694876.htmlhttp://lgbolgger.iteye.com/blog/2170522
