Spring+SpringMVC+Shiro+Redis+Maven权限管理

Shiro Demo 准备工作

运行前申明
  1. 请看完本页面的所有细节,对你掌握这个项目来说很重要,别一上来就搞,你不爽,我也不爽。
  2. 本项目需要一定的Java功底,需要对SpringMvcMybatis,有基本的了解,其次对Redis有了解和使用更佳。
  3. 本项目理论上,只需要一个Redis,然后一个Mysql和一个有Maven环境的开发工具即可运行起来。
运行步骤
  1. 从 Github 下载源码(不定期更新和修复BUG),导入到EclipseMyEclipesIdea类似开发工具。
  2. 解决编译错误,修改JDK1.7以上(请勿使用工具自带JDK)。
  3. Mysql数据库中创建一个数据库,库名随便。
  4. 从项目/init/sql/下,先执行tables.sql创建表,再运行init.data.sql插入初始化数据。
  5. 再修改配置jdbc.properties把数据库链接改成您的。
  6. 安装Redis服务,如果您没用过,或者没安装,请看这里==>Redis 安装,以及注意事项都在里面有说明。
  7. 安装完毕后,修改配置:spring-cache.xml,如果是本地,无序修改,启动Redis,如对Redis不了解的同学,建议别设置密码。
  8. 运行项目,如果还有错误请参考异常信息,并解决,如果实在不能解决,请加QQ群交流,群需要付费5元,加群请看右侧菜单。
  9. 项目帐号和线上Demo一致:管理员帐号:admin,密码:sojson.com 如果密码错误,请用 sojson
线上Demo说明
  1. Demo已经部署到线上,地址是:http://shiro.itboy.net
  2. 管理员帐号:admin,密码:sojson.com 如果密码错误,请用 sojson
  3. 你可以注册自己的帐号,然后用管理员赋权限给你自己的帐号,但是,每20分钟会把数据初始化一次。建议自己下载源码,让Demo跑起来,然后跑的更快,有问题加群解决。

Shiro Demo 源码下载

Shiro Demo 非Maven项目依赖包下载:点我下载

Github 0.1版本下载:https://github.com/baichengzhou/SpringMVC-Mybatis-shiro,(请下载0.2版本)

Github 0.2版本下载:https://github.com/baichengzhou/SpringMVC-Mybatis-Shiro-redis-0.2

Shiro Demo 0.2版本介绍:http://www.sojson.com/blog/165.html

Shiro Demo 0.2版本主要解决的问题为0.1版本出现的问题和BUG。

Shiro Demo 0.2版本为Shiro Demo 0.1的升级版本

PS:请选用0.2版本,这样你遇到的问题会比较少。
升级内容:
  1. 修复了些许BUG,优化了语法。
  2. 0.1版本限制较多,比如要部署到Tomcat Root下才能正常运行,就是用http://localhost:8080方式访问。
  3. 0.2版本可以采用目录访问,如:http://localhost:8080/shiro.demo/,默认项目名称为/shiro.demo/

Shiro 简介

Apache Shiro  Java  的一个安全框架。我们经常看到它被拿来和 Spring   Security  来对比。大部分人认为 Shiro   Security  要简单。我的观点赞成一半一半吧。

首先 Shiro  确实和 Security  是同类型的框架,主要用来做安全,也就是我们俗称的权限校验(控制)。居多人对 Shiro  的定义为好入门。

我选型为 Shiro  ,主要的原因扩展太easy了,而且我要的功能它都有。

本教程开发环境

本教程Jar包管理是 Maven  ,所以如果是 Maven  项目下载Demo后可以直接使用,如果是普通的Java Web项目,那么请在下面下载所有依赖包。

本教程开发工具是Myecilpse8.5

本教程编码格式为UTF-8

本教程JDK为1.7,请勿使用自带工具JDK。

本教程Mysql为5.3版本是以上。

Redis 版本随意。

本教程Spring版本为4.2.5

前端页面采用Bootstrap 3.2

本教程包含的内容

  1. SSM(SpringMVC + Spring + Mybatis)框架的增删改查(含分页),所以如果框架小白也是可以看看的。
  2. View层主要是Freemarker,但是为了考虑到好多人还使用的是JSP,也有一个页面是用JSP实现的,并且框架支持Freemarker 和 JSPView展示(优先找Freemarker)。
  3. Shiro + Redis 的集成,也提供Ehcache的依赖Jar。
  4. Shiro 初始权限动态加载。
  5. Shiro 自定义权限校验Filter定义,及功能实现。
  6. Shiro Ajax请求权限不满足,拦截后解决方案。
  7. Shiro Freemarker标签使用。
  8. Shiro JSP标签使用。
  9. Shiro 登录后跳转到最后一个访问的页面。
  10. 用户禁止登录Demo
  11. 在线显示,在线用户管理(踢出登录)。
  12. 登录注册密码加密传输Demo(详细请见下面讲解)。
  13. 密码修改。
  14. 用户个人中心。
  15. 权限的增删改查。
  16. 角色的增删改查。
  17. 权限->角色->用户之间的关系维护。
  18. 管理员权限的自动添加(当有一个权限创建,自动添加到管理员角色下,保证管理员是最大权限)。
  19. Spring定时任务数据化数据。
  20. 集成多种验证码(包括动态的gif验证码哦)。
  21. 一个帐号多处登录限制,踢出用户。
  22. 后续会陆陆续续升级... ...

一、SSM(SpringMVC + Mybatis)框架的增删改查(含分页)

本教程是SSM(SpringMVC + Spring + Mybatis + Freemarker + JSP) + Shiro + Redis 做的整体Demo,其他框架需要自己自行解决,所以不做其他框架的讲解,其实是大同小异。

Controller ==> Service(事务控制层) ==> Dao ==> SqlMapper ==> Mysql

二、View层 Freemarker,JSP

通用View层配置在spring-mvc.xml中的以【通用试图解析器】注释标注的区间配置。

三、Shiro + Redis 的集成,也提供Ehcache的依赖Jar。

Redis 缓存配置主要在spring-cache.xml中。对应的所有Cache 相关 Java  代码在package:com.sojson.core.shiro.cache

四、Shiro 初始权限动态加载。

我们一般是这么加载的。在spring-shiro.xml中配置


  
  
  1. <property name="filterChainDefinitions" >
  2. <value>
  3. /** = anon
  4. /page/login.jsp = anon
  5. /page/register/* = anon
  6. /page/index.jsp = authc
  7. /page/addItem* = authc,roles[数据管理员]
  8. /page/file* = authc,roleOR[普通用户,数据管理员]
  9. /page/listItems* = authc,roleOR[数据管理员,普通用户]
  10. /page/showItem* = authc,roleOR[数据管理员,普通用户]
  11. /page/updateItem*=authc,roles[数据管理员]
  12. </value>
  13. </property>

本教程采用动态加载,你可以从数据库里读取然后拼接成shiro要的数据。


  
  
  1. <property name="filterChainDefinitions" value="#\{shiroManager.loadFilterChainDefinitions()\}"/>

配置文件方式加载详细讲解:http://www.sojson.com/blog/148.html

五、Shiro 自定义权限校验Filter定义,及功能实现。

Shiro Filter在package:com.sojson.core.shiro.filter,具体配置在spring-shiro.xml中。定义了5个拦截器,具体功能看代码以及代码注释。


  
  
  1. <bean id="shiroManager" class="com.sojson.core.shiro.service.impl.ShiroManagerImpl"/>
  2. <bean id="login" class="com.sojson.core.shiro.filter.LoginFilter"/>
  3. <bean id="role" class="com.sojson.core.shiro.filter.RoleFilter"/>
  4. <bean id="permission" class="com.sojson.core.shiro.filter.PermissionFilter"/>
  5. <bean id="simple" class="com.sojson.core.shiro.filter.SimpleAuthFilter"/>

  
  
  1. <property name="filters">
  2. <util:map>
  3. <entry key="login" value-ref="login"></entry>
  4. <entry key="role" value-ref="role"></entry>
  5. <entry key="simple" value-ref="simple"></entry>
  6. <entry key="permission" value-ref="permission"></entry>
  7. </util:map>
  8. </property>

六、Shiro Ajax请求权限不满足,拦截后解决方案。

这里有一个前提,我们知道Ajax不能做页面redirectforward跳转,所以Ajax请求假如没登录,那么这个请求给用户的感觉就是没有任何反应,而用户又不知道用户已经退出了。解决代码如下:


  
  
  1. //Java代码,判断如果是Ajax请求,然后并且没登录,那么就给予返回JSON,login_status = 300,message = 当前用户没有登录!
  2. if (ShiroFilterUtils.isAjax(request)) {// ajax请求
  3. Map<String,String> resultMap = new HashMap<String, String>();
  4. LoggerUtils.debug(getClass(), "当前用户没有登录,并且是Ajax请求!");
  5. resultMap.put("login_status", "300");
  6. resultMap.put("message", "\u5F53\u524D\u7528\u6237\u6CA1\u6709\u767B\u5F55\uFF01");//当前用户没有登录!
  7. ShiroFilterUtils.out(response, resultMap);
  8. }


  
  
  1. //前端代码
  2. if(result.login_status == 300){
  3. layer.msg(result.message);//当前用户没有登录!
  4. }

七、Shiro Freemarker标签使用。

Freemarker使用Shiro 标签的介绍:http://www.sojson.com/blog/143.html

八、Shiro JSP标签使用。

JSP使用Shiro 标签的介绍:http://www.sojson.com/blog/144.html

九、Shiro 登录后跳转到最后一个访问的页面。

 Java  中就可以这样获取上一个地址:


  
  
  1. //上一个浏览的非Ajax的地址,在登录后,取得地址,如果不为null,那么就跳转过去。
  2. String url = (String) request.getAttribute(WebUtils.FORWARD_REQUEST_URI_ATTRIBUTE);
  3. //shiro也有他的方法。详细看下面。

如果需要保存登录之前的Request信息,那么需要在Login拦截的Filter中先保存:


  
  
  1. @Override
  2. protected boolean onAccessDenied(ServletRequest request, ServletResponse response)
  3. throws Exception {
  4. //保存Request和Response,登录后可以取到
  5. saveRequestAndRedirectToLogin(request, response);
  6. return Boolean.FALSE ;
  7. }
  8. //登录后,取到之前的Request中的一些信息。
  9. SavedRequest saveRequest = WebUtils.getSavedRequest(request);
  10. saveRequest.getMethod();//之前的请求方法
  11. saveRequest.getQueryString();//之前请求的条件
  12. saveRequest.getRequestURI();//之前请求的路径
  13. saveRequest.getRequestUrl();//之前请求的全路径

十、用户禁止登录Demo

这个功能其实是一个改变用户数据库表里的一个字段,本Demo中:1:有效,0:禁止登录

然后踢出用户登录状态。代码详细请查看CustomSessionManager.java类的forbidUserById(Long id, Long status)方法。

而再次登录的话,需要再登录,而登录的地方限制了用户状态为(0:禁止登录)的用户登录。


  
  
  1. /**
  2. * 查询要禁用的用户是否在线。
  3. * @param id 用户ID
  4. * @param status 用户状态
  5. */
  6. public void forbidUserById(Long id, Long status) {
  7. //获取所有在线用户
  8. for(UserOnlineBo bo : getAllUser()){
  9. Long userId = bo.getId();
  10. //匹配用户ID
  11. if(userId.equals(id)){
  12. //获取用户Session
  13. Session session = shiroSessionRepository.getSession(bo.getSessionId());
  14. //标记用户Session
  15. SessionStatus sessionStatus = (SessionStatus) session.getAttribute(SESSION_STATUS);
  16. //是否踢出 true:有效,false:踢出。
  17. sessionStatus.setOnlineStatus(status.intValue() == 1);
  18. //更新Session
  19. customShiroSessionDAO.update(session);
  20. }
  21. }
  22. }

十一、在线显示,在线用户管理(踢出登录)

上面的功能依赖这个功能。从Redis中获取所有有效的Session


  
  
  1. /**
  2. * 获取所有的有效Session用户
  3. * @return
  4. */
  5. public List getAllUser() {
  6. //获取所有session
  7. Collection sessions = customShiroSessionDAO.getActiveSessions();
  8. List list = new ArrayList();
  9. for (Session session : sessions) {
  10. UserOnlineBo bo = getSessionBo(session);
  11. if(null != bo){
  12. list.add(bo);
  13. }
  14. }
  15. return list;
  16. }

踢出后,不能直接退出,要不然用户感觉莫名其妙。所有增加了一个Filter。SimpleAuthFilter.java如果标记为踢出,会提示用户。具体查看源码以及配合项目的使用。

十二、登录注册密码加密传输

这个地方好多人纠结的。比如密码过于简单,即使加密后也能破解。如我们把密码:123456,加密后就是:e10adc3949ba59abbe56e057f20f883e

这个很容易被识别,导致不安全,现在市面上的MD5破解其实就是把常用的数字,字母进行先加密,然后对比,美其名曰破解MD5。

那怎么能让用户即使使用很简单的密码,也发现不了?

本Demo的实现方式是:MD5(登录帐号 + “固定值” + 密码),把这个作为密码,这样,基本是不可能猜的出来。


  
  
  1. //Java代码。UserManager.md5Pswd(UUser user);
  2. /**
  3. * 加工密码,和登录一致。
  4. * @param user
  5. * @return
  6. */
  7. public static UUser md5Pswd(UUser user){
  8. //密码为 email + '#' + pswd,然后MD5
  9. user.setPswd(md5Pswd(user.getEmail(),user.getPswd()));
  10. return user;
  11. }
  12. /**
  13. * 字符串返回值
  14. * @param email
  15. * @param pswd
  16. * @return
  17. */
  18. public static String md5Pswd(String email ,String pswd){
  19. pswd = String.format("%s#%s", email,pswd);
  20. pswd = MathUtil.getMD5(pswd);
  21. return pswd;
  22. }

  
  
  1. //JS代码
  2. var pswd = MD5(username +"#" + password);

十三、密码修改

不讲了,和上面原理一致,然后具体看Demo。

十四、用户个人中心

包含的功能有[个人资料,资料修改,密码修改,我的权限],具体看Demo。

十五、权限的增删改查。

Demo的设计是遵循RBAC3的思想。http://www.sojson.com/blog/142.html

RBAC个人理解介绍:http://www.sojson.com/blog/141.html

具体实现看Demo。

十六、角色的增删改查

角色增删改查

十七、权限->角色->用户之间的关系维护

把权限赋给角色。

权限赋给角色

把角色赋给用户。

角色权限

十八、管理员权限的自动添加

这里每次添加一个权限,都会添加到“管理员”角色下,保证“管理员”角色拥有最大权限。

十九、Spring定时任务数据初始化

这个Demo因为是开放的,所以创建了一个定时任务。每20分钟执行一次,用Mysql存储过程重新创建表,重新插入初始化数据。

具体数据看项目中的init/sql下的tables.sql(初始化表),init.data.sql(初始化数据)。


  
  
  1. //定时任务配置文件spring-timer.xml
  2. <task:executor id="executor" pool-size="5" />
  3. <task:scheduler id="scheduler" pool-size="10" />
  4. <task:annotation-driven executor="executor" scheduler="scheduler" />
  5. //Java 代码 RoleServiceImpl.java
  6. /**
  7. * 每20分钟执行一次
  8. */
  9. @Override
  10. @Scheduled(cron = "0 0/20 * * * ? ")
  11. public void initData() {
  12. roleMapper.initData();
  13. }

二十、集成验证码

shiro 验证码

项目中package:com.sojson.common.utils.vcode包是验证码的封装包。

并且提供了一个VerifyCodeUtils.java 的验证码工具类。

使用方法参见:CommonController.java类中的getVCode()方法和getGifCode()方法。

验证码详细介绍
Java生成验证码合集(一)简单版 
Java生成验证码合集(二)GJF版 

二十一、一个帐号多处登录限制,踢出用户。

项目中我们会用到单点登录,还有用到单个账号怎么限制同时只能一个人在线?

Shiro教程(十一)Shiro 控制并发登录人数限制实现,登录踢出实现:http://www.sojson.com/blog/158.html

如果不是Maven项目,下载依赖包。

依赖Jar包下载:

项目依赖Jar包,或者请加QQ群:259217951(群文件内有,有问题可以交流。)。

备注:点击文件名下载,附件源来自云端,只能在本站下载。复制下载链接无效。

Shiro + SSM框架 Demo 源码下载。

源码下载

Shiro_SSM_0.1版本下载(求你了,别下。)

Shiro_SSM_0.2版本下载(最后更新时间,2017年5月9日 )

备注:点击文件名下载,附件源来自云端,只能在本站下载。复制下载链接无效。

如果本文对你有帮助,那么请你赞助我,让我更有激情的写下去,帮助更多的人。

¥我需要走的更远,点击我 赞助。 如果还有疑问,点击我加群,为你提供最好的解答。

版权所属:SO JSON在线解析

原文地址:http://www.sojson.com/shiro

转载时必须以链接形式注明原始出处及本声明。

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
本项目详细介绍请看:http://www.sojson.com/shiro (强烈推荐) Demo已经部署到线上,地址是http://shiro.itboy.net, 管理员帐号:admin,密码:sojson.com 如果密码错误,请用sojson。 PS:你可以注册自己的帐号,然后用管理员赋权限给你自己的帐号,但是,每20分钟会把数据初始化一次。建议自己下载源码,让Demo跑起来,然后跑的更快,有问题加群解决。 声明: 本人提供这个Shiro + SpringMvc + Mybatis + Redis 的Demo 本着学习的态度,如果有欠缺和不足的地方,给予指正,并且多多包涵。 “去其糟粕取其精华”。如果觉得写的好的地方就给个赞,写的不好的地方,也请多多包涵。 使用过程: 1.创建数据库。 创建语句 :tables.sql 2.插入初始化数据 插入初始化数据:init.data.sql 3.运行。 管理员帐号:admin 密码:sojson ps:定时任务的sql会把密码改变为sojson.com 新版本说明:http://www.sojson.com/blog/164.html 和 http://www.sojson.com/blog/165.html 主要解决是之前说的问题:Shiro 教程,关于最近反应的相关异常问题,解决方法合集。 项目在本页面的附件中提取。 一、Cache配置修改。 配置文件(spring-cache.xml )中已经修改为如下配置: <!-- redis 配置,也可以把配置挪到properties配置文件中,再读取 --> <!-- 这种 arguments 构造的方式,之前配置有缺点。 这里之前的配置有问题,因为参数类型不一致,有时候jar和环境的问题,导致参数根据index对应,会处理问题, 理论上加另一个 name,就可以解决,现在把name 和type都加上,更保险。 --> 二、登录获取上一个URL地址报错。 当没有获取到退出前的request ,为null 的时候会报错。在(UserLoginController.java )135行处有所修改。 /** * shiro 获取登录之前的地址 * 之前0.1版本这个没判断空。 */ SavedRequest savedRequest = WebUtils.getSavedRequest(request); String url = null ; if(null != savedRequest){ url = savedRequest.getRequestUrl(); } /** * 我们平常用的获取上一个请求的方式,在Session不一致的情况下是获取不到的 * String url = (String) request.getAttribute(WebUtils.FORWARD_REQUEST_URI_ATTRIBUTE); */ 三、删除了配置文件中的cookie写入域的问题。 在配置文件里(spring-shiro.xml )中的配置有所修改。 <!-- 会话Cookie模板 --> <!--cookie的name,我故意取名叫xxxxbaidu --> <!--cookie的有效时间 --> <!-- 配置存储Session Cookie的domain为 一级域名 --> 上面配置是去掉了 Session 的存储Key 的作用域,之前设置的.itboy.net ,是写到当前域名的 一级域名 下,这样就可以做到N 个 二级域名 下,三级、四级....下 Session 都是共享的。 <!-- 用户信息记住我功能的相关配置 --> <!-- 配置存储rememberMe Cookie的domain为 一级域名 --> <!-- 30天时间,记住我30天 --> 记住我登录的信息配置。和上面配置是一样的道理,可以在相同 一级域名 下的所有域名都可以获取到登录的信息。 四、简单实现了单个帐号只能在一处登录。 我们在其他的系统中可以看到,单个帐号只允许一人使用,在A处登录了,B处再登录,那A处就被踢出了。如下图所示。 但是此功能不是很完美,当A处被踢出后,再重新登录,这时候B处反应有点慢,具体我还没看,因为是之前加的功能,现在凌晨了,下次我有空再瞧瞧,同学你也可以看看,解决了和我说一声,我把功能修复。 五、修复功能(BUG) 1.修复权限添加功能BUG。 之前功能有问题,每当添加一个权限的时候,默认都给角色为“管理员”的角色默认添加当前新添加的权限。这样达到管理员的权限永远是最大的。由于代码有BUG ,导致所有权限删除了。现已修复。 2.修复项目只能部署到Root目录下的问题。 问题描述:之前项目只能部署到Root 下才能正常运行,目前已经修复,可以带项目路径进行访问了,之前只能这样访问,http://localhost:8080 而不能http://localhost:8080/shiro.demo/ 访问,目前是可以了。 解决方案:在 FreeMarkerViewExtend.java 33行处 增加了BasePath ,通过BasePath 来控制请求目录,在 Freemarker 中可以自由使用,而 JSP 中是直接在 JSP 中获取BasePath 使用。 解决后遗症:因为我们的权限是通过URL 来控制的,那么增加了项目的目录,导致权限不能正确的判断,再加上我们的项目名称(目录)可以自定义,导致更不好判断。 后遗症解决方案:PermissionFilter.java 50行处 解决了这个问题,详情请看代码和注释,其实就是replace 了一下。 HttpServletRequest httpRequest = ((HttpServletRequest)request); /** * 此处是改版后,为了兼容项目不需要部署到root下,也可以正常运行,但是权限没设置目前必须到root 的URI, * 原因:如果你把这个项目叫 ShiroDemo,那么路径就是 /ShiroDemo/xxxx.shtml ,那另外一个人使用,又叫Shiro_Demo,那么就要这么控制/Shiro_Demo/xxxx.shtml * 理解了吗? * 所以这里替换了一下,使用根目录开始的URI */ String uri = httpRequest.getRequestURI();//获取URI String basePath = httpRequest.getContextPath();//获取basePath if(null != uri && uri.startsWith(basePath)){ uri = uri.replace(basePath, ""); } 3.项目启动的时候报错,关于JNDI的错误提示。 其实也不是错,但是看着不舒服,所以还得解决这个问题。解决这个问题需要在web.xml 中的开始部位加入以下代码。 spring.profiles.active dev spring.profiles.default dev spring.liveBeansView.mbeanDomain dev 4.项目Maven打包问题。 打包的时候,不同版本的 Eclipse 还有IDEA 会有打包打不进去Mapper.xml 文件,这个时候要加如下代码(群里同学提供的)。 src/main/java **/*.properties **/*.xml false 在 标签内加入即可,如果还是不能解决,那么请你加群(改名后)说明你的问题,有人会回答你。 5.Tomcat7以上在访问JSP页面的时候,提示JSTL错误。 这个错误是因为Tomcat7 中没有 JSTL 的jar包,现在已经在项目pom.xml 中增加了如下 jar 的引入管理。 javax.servlet jstl 1.2 javax.servlet jsp-api 2.0 provided 如果还是不能解决问题,请在官方群(群号:259217951)内搜索“jstl” 如图下载依赖包。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值