概述
詳細
一、項目介紹(准備工作)
運行前申明
-
請看完本頁面的所有細節,對你掌握這個項目來說很重要,別一上來就搞,你不爽,我也不爽。
-
本項目需要一定的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大師發表,拒絕轉載,轉載需要作者授權