基于SSM + Redis的Shiro权限管理项目
概述
详细
一、项目介绍(准备工作)
运行前申明
请看完本页面的所有细节,对你掌握这个项目来说很重要,别一上来就搞,你不爽,我也不爽。
本项目需要一定的Java功底,需要对
SpringMvc
,Mybatis
,有基本的了解,其次对Redis
有了解和使用更佳。本项目理论上,只需要一个
Redis
,然后一个Mysql
和一个有Maven
环境的开发工具即可运行起来。对Reids没有了解,请看这里:对Redis的理解,Redis是什么,Redis和Memcache谁快?。
运行步骤
下载源码,导入到
Eclipse
、MyEclipes
、Idea
类似开发工具。解决编译错误,修改
JDK
为1.7
以上(请勿使用工具自带JDK
)。在
Mysql
数据库中创建一个数据库,库名随便,数据库版本为5.6(必要条件,否则部分语法不支持)。从项目
/init/sql/
下,先执行tables.sql
创建表,再运行init.data.sql
插入初始化数据。再修改配置
jdbc.properties
把数据库链接改成您的。安装Redis服务,如果您没用过,或者没安装,请看这里==>Redis 安装,以及注意事项都在里面有说明。Redis启动报错请看这里:Please see the documentation included with the binary distributions for more details on the --maxheap flag.
安装完毕后,修改配置:
spring-cache.xml
,如果是本地,无序修改,启动Redis
,如对Redis
不了解的同学,建议别设置密码。
二、运行效果
项目帐号和线上Demo一致:管理员帐号:admin,密码:sojson.com 如果密码错误,请用 sojson
线上 Demo:http://shiro.itboy.net/
截图如下:
三、程序实现过程
1、SSM(SpringMVC + Mybatis)框架的增删改查(含分页)
本教程是SSM(SpringMVC + Spring + Mybatis + Freemarker + JSP)
+ Shiro + Redis 做的整体Demo,其他框架需要自己自行解决,所以不做其他框架的讲解,其实是大同小异。
Controller
==> Service
(事务控制层) ==> Dao
==> SqlMapper
==> Mysql
2、View层 Freemarker,JSP
通用View
层配置在spring-mvc.xml
中的以【通用试图解析器】注释标注的区间配置。
3、Shiro + Redis 的集成,也提供Ehcache的依赖Jar
Redis
缓存配置主要在spring-cache.xml
中。对应的所有Cache 相关Java代码在package:com.sojson.core.shiro.cache
中
4、Shiro 初始权限动态加载
我们一般是这么加载的。在spring-shiro.xml
中配置
<property name="filterChainDefinitions" >
<value>
/** = anon
/page/login.jsp = anon
/page/register/* = anon
/page/index.jsp = authc
/page/addItem* = authc,roles[数据管理员]
/page/file* = authc,roleOR[普通用户,数据管理员]
/page/listItems* = authc,roleOR[数据管理员,普通用户]
/page/showItem* = authc,roleOR[数据管理员,普通用户]
/page/updateItem*=authc,roles[数据管理员]
</value>
</property>
本教程采用动态加载,你可以从数据库里读取然后拼接成shiro要的数据。
<property name="filterChainDefinitions" value="#\{shiroManager.loadFilterChainDefinitions()\}"/>
配置文件方式加载详细讲解:http://www.sojson.com/blog/148.html
5、Shiro 自定义权限校验Filter定义,及功能实现
Shiro Filter在package:com.sojson.core.shiro.filter
,具体配置在spring-shiro.xml
中。定义了5个拦截器,具体功能看代码以及代码注释。
<bean id="shiroManager" class="com.sojson.core.shiro.service.impl.ShiroManagerImpl"/>
<bean id="login" class="com.sojson.core.shiro.filter.LoginFilter"/>
<bean id="role" class="com.sojson.core.shiro.filter.RoleFilter"/>
<bean id="permission" class="com.sojson.core.shiro.filter.PermissionFilter"/>
<bean id="simple" class="com.sojson.core.shiro.filter.SimpleAuthFilter"/>
<property name="filters">
<util:map>
<entry key="login" value-ref="login"></entry>
<entry key="role" value-ref="role"></entry>
<entry key="simple" value-ref="simple"></entry>
<entry key="permission" value-ref="permission"></entry>
</util:map>
</property>
6、Shiro Ajax请求权限不满足,拦截后解决方案
这里有一个前提,我们知道Ajax不能做页面redirect
和forward
跳转,所以Ajax请求假如没登录,那么这个请求给用户的感觉就是没有任何反应,而用户又不知道用户已经退出了。解决代码如下:
//Java代码,判断如果是Ajax请求,然后并且没登录,那么就给予返回JSON,login_status = 300,message = 当前用户没有登录!
if (ShiroFilterUtils.isAjax(request)) {// ajax请求
Map<String,String> resultMap = new HashMap<String, String>();
LoggerUtils.debug(getClass(), "当前用户没有登录,并且是Ajax请求!");
resultMap.put("login_status", "300");
resultMap.put("message", "\u5F53\u524D\u7528\u6237\u6CA1\u6709\u767B\u5F55\uFF01");//当前用户没有登录!
ShiroFilterUtils.out(response, resultMap);
}
//前端代码
if(result.login_status == 300){
layer.msg(result.message);//当前用户没有登录!
}
7、Shiro Freemarker标签使用
Freemarker使用Shiro 标签的介绍:http://www.sojson.com/blog/143.html
8、Shiro JSP标签使用
JSP使用Shiro 标签的介绍:http://www.sojson.com/blog/144.html
9、Shiro 登录后跳转到最后一个访问的页面
在Java中就可以这样获取上一个地址:
//上一个浏览的非Ajax的地址,在登录后,取得地址,如果不为null,那么就跳转过去。
String url = (String) request.getAttribute(WebUtils.FORWARD_REQUEST_URI_ATTRIBUTE);
//shiro也有他的方法。详细看下面。
如果需要保存登录之前的Request信息,那么需要在Login拦截的Filter中先保存:
@Override
protected boolean onAccessDenied(ServletRequest request, ServletResponse response)
throws Exception {
//保存Request和Response,登录后可以取到
saveRequestAndRedirectToLogin(request, response);
return Boolean.FALSE ;
}
//登录后,取到之前的Request中的一些信息。
SavedRequest saveRequest = WebUtils.getSavedRequest(request);
saveRequest.getMethod();//之前的请求方法
saveRequest.getQueryString();//之前请求的条件
saveRequest.getRequestURI();//之前请求的路径
saveRequest.getRequestUrl();//之前请求的全路径
10、用户禁止登录Demo
这个功能其实是一个改变用户数据库表里的一个字段,本Demo中:1:有效,0:禁止登录
然后踢出用户登录状态。代码详细请查看CustomSessionManager.java
类的forbidUserById(Long id, Long status)
方法。
而再次登录的话,需要再登录,而登录的地方限制了用户状态为(0
:禁止登录)的用户登录。
/**
* 查询要禁用的用户是否在线。
* @param id 用户ID
* @param status 用户状态
*/
public void forbidUserById(Long id, Long status) {
//获取所有在线用户
for(UserOnlineBo bo : getAllUser()){
Long userId = bo.getId();
//匹配用户ID
if(userId.equals(id)){
//获取用户Session
Session session = shiroSessionRepository.getSession(bo.getSessionId());
//标记用户Session
SessionStatus sessionStatus = (SessionStatus) session.getAttribute(SESSION_STATUS);
//是否踢出 true:有效,false:踢出。
sessionStatus.setOnlineStatus(status.intValue() == 1);
//更新Session
customShiroSessionDAO.update(session);
}
}
}
11、在线显示,在线用户管理(踢出登录)
上面的功能依赖这个功能。从Redis中获取所有有效的Session。
/**
* 获取所有的有效Session用户
* @return
*/
public List getAllUser() {
/*获取所有session*/
Collection sessions = customShiroSessionDAO.getActiveSessions();
List list = new ArrayList(); for (Session session : sessions) {
UserOnlineBo bo = getSessionBo(session);
if(null != bo){
list.add(bo);
}
}
return list;
}
踢出后,不能直接退出,要不然用户感觉莫名其妙。所有增加了一个Filter。SimpleAuthFilter.java
如果标记为踢出,会提示用户。具体查看源码以及配合项目的使用。
12、登录注册密码加密传输
这个地方好多人纠结的。比如密码过于简单,即使加密后也能破解。如我们把密码:123456
,加密后就是:e10adc3949ba59abbe56e057f20f883e
这个很容易被识别,导致不安全,现在市面上的MD5破解其实就是把常用的数字,字母进行先加密,然后对比,美其名曰破解MD5。
那怎么能让用户即使使用很简单的密码,也发现不了?
本Demo的实现方式是:MD5(登录帐号 + “固定值” + 密码),把这个作为密码,这样,基本是不可能猜的出来。
//Java代码。UserManager.md5Pswd(UUser user);
/**
* 加工密码,和登录一致。
* @param user
* @return
*/
public static UUser md5Pswd(UUser user){
//密码为 email + '#' + pswd,然后MD5
user.setPswd(md5Pswd(user.getEmail(),user.getPswd()));
return user;
}
/**
* 字符串返回值
* @param email
* @param pswd
* @return
*/
public static String md5Pswd(String email ,String pswd){
pswd = String.format("%s#%s", email,pswd);
pswd = MathUtil.getMD5(pswd);
return pswd;
}
//JS代码
var pswd = MD5(username +"#" + password);
13、密码修改
不讲了,和上面原理一致,然后具体看Demo。
14、用户个人中心
包含的功能有[个人资料,资料修改,密码修改,我的权限],具体看Demo。
15、权限的增删改查。
本Demo
的设计是遵循RBAC3的思想。http://www.sojson.com/blog/142.html
RBAC个人理解介绍:http://www.sojson.com/blog/141.html
具体实现看Demo。
16、角色的增删改查
17、权限->角色->用户之间的关系维护
把权限赋给角色。
把角色赋给用户。
18、管理员权限的自动添加
这里每次添加一个权限,都会添加到“管理员”角色下,保证“管理员”角色拥有最大权限。
19、Spring定时任务数据初始化
这个Demo
因为是开放的,所以创建了一个定时任务。每20分钟执行一次,用Mysql存储过程重新创建表,重新插入初始化数据。
具体数据看项目中的init/sql
下的tables.sql(初始化表),init.data.sql(初始化数据)。
//定时任务配置文件spring-timer.xml
<task:executor id="executor" pool-size="5" />
<task:scheduler id="scheduler" pool-size="10" />
<task:annotation-driven executor="executor" scheduler="scheduler" />
//Java 代码 RoleServiceImpl.java
/**
* 每20分钟执行一次
*/
@Override
@Scheduled(cron = "0 0/20 * * * ? ")
public void initData() {
roleMapper.initData();
}
20、集成验证码
项目中package:com.sojson.common.utils.vcode
包是验证码的封装包。
并且提供了一个VerifyCodeUtils.java 的验证码工具类。
使用方法参见:CommonController.java
类中的getVCode()
方法和getGifCode()
方法。
Java生成验证码合集(一)简单版、
Java生成验证码合集(二)GJF版。
四、项目代码截图
注:本文著作权归作者,由demo大师发表,拒绝转载,转载需要作者授权
基于SSM + Redis的Shiro权限管理项目的更多相关文章
- [转]Asp.Net大型项目实践(11)-基于MVC Action粒度的权限管理【续】【源码在这里】(在线demo,全部源码)
本文转自:http://www.cnblogs.com/legendxian/archive/2010/01/25/1655551.html 接上篇Asp.Net大型项目实践(10)-基于MVC Ac ...
- (39.2). Spring Boot Shiro权限管理【从零开始学Spring Boot】
(本节提供源代码,在最下面可以下载) (4). 集成Shiro 进行用户授权 在看此小节前,您可能需要先看: http://412887952-qq-com.iteye.com/blog/229973 ...
- (39.1) Spring Boot Shiro权限管理【从零开始学Spring Boot】
(本节提供源代码,在最下面可以下载)距上一个章节过了二个星期了,最近时间也是比较紧,一直没有时间可以写博客,今天难得有点时间,就说说Spring Boot如何集成Shiro吧.这个章节会比较复杂,牵涉 ...
- Spring Boot Shiro 权限管理 【转】
http://blog.csdn.net/catoop/article/details/50520958 主要用于备忘 本来是打算接着写关于数据库方面,集成MyBatis的,刚好赶上朋友问到Shiro ...
- shiro权限管理的框架-入门
shiro权限管理的框架 1.权限管理的概念 基本上涉及到用户参与的系统都要进行权限管理,权限管理属于系统安全的范畴,权限管理实现对用户访问系统的控制,按照安全规则或者安全策略控制用户可以访问而且只能 ...
- (39.4) Spring Boot Shiro权限管理【从零开始学Spring Boot】
在读此文章之前您还可能需要先了解: (39.1) Spring Boot Shiro权限管理[从零开始学Spring Boot] http://412887952-qq-com.iteye.com/b ...
- (39.3) Spring Boot Shiro权限管理【从零开始学Spring Boot】
在学习此小节之前您可能还需要学习: (39.1) Spring Boot Shiro权限管理[从零开始学Spring Boot] http://412887952-qq-com.iteye.com/b ...
- Spring Boot Shiro 权限管理
Spring Boot Shiro 权限管理 标签: springshiro 2016-01-14 23:44 94587人阅读 评论(60) 收藏 举报 .embody{ padding:10px ...
- (补漏)Springboot2.0 集成shiro权限管理
原文Springboot2.0 集成shiro权限管理 一.关于停止使用外键. 原本集成shiro建立用户.角色.权限表的时候使用了外键,系统自动创建其中两个关联表,用@JoinTable.看起来省事 ...
随机推荐
- IndiaHacks 2016 - Online Edition (Div. 1 + Div. 2) C. Bear and Up-Down 暴力
C. Bear and Up-Down 题目连接: http://www.codeforces.com/contest/653/problem/C Description The life goes ...
- leetcode132. Palindrome Partitioning II
leetcode132. Palindrome Partitioning II 题意: 给定一个字符串s,分区使分区的每个子字符串都是回文. 返回对于s的回文分割所需的最小削减. 例如,给定s =&q ...
- 引用计数的cocos2dx对象内存管理和直接new/delete box2d对象内存管理冲突的解决方法
转载请注明: http://blog.csdn.net/herm_lib/article/details/9316601 项目中用到了cocos2dx和box2d,cocos2dx的内存是基于引用计数 ...
- iOS: 如何获取ios设备的当前IP地址
有的时候,我们项目上线后,需要根据ip地址去统计不同地区的用户情况,此时IP地址的收取显得尤其重要,一般情况下,在用户登录时去获取用户的ip是准确的,当然实时追踪ip的变化而统计是更安全可靠的. ip ...
- 一次WEB前端优化尝试
今天对自己做的项目中的一个设计器界面加载速度上进行了优化,因为页面在加载的时候,感觉有点慢.首先,我用firefox的yslow和chrome的pagespeed进行了测试,效果如下,分数有点不同,但 ...
- js执行eval()抛出异常SyntaxError
try{ eval("("+data+")"); }catch(err) { location.href = window.location.href; }
- PHP判断{函数/类/方法/属性}是否存在
1.php判断系统函数或自己写的函数是否存在 bool function_exists ( string $function_name ) 判断函数是否已经定义,例如: if(function_exi ...
- 【Python】Django用户、认证、鉴权模块使用
此文是总结Django官方网站里面的Document的文章 User authentication in Django http://www.djangoproject.com/documentati ...
- CarbonData编译与安装
原文连接 http://xiguada.org/carbondata_compile/ CarbonData是啥? CarbonData is a fully indexed columnar and ...
- [Algorithm -- Dynamic programming] How Many Ways to Decode This Message?
For example we have 'a' -> 1 'b' -> 2 .. 'z' -> 26 By given "12", we can decode t ...