Apache Shiro 權限控制實戰(zhàn),權限控制Demo,SpringMVC + Mybatis + Shiro 項目下載

Shiro Demo 準備工作

運行前申明

請看完本頁面的所有細節(jié),對你掌握這個項目來說很重要,別一上來就搞,你不爽,我也不爽。

本項目需要一定的Java功底,需要對SpringMvc,Mybatis,有基本的了解,其次對Redis有了解和使用更佳。

本項目理論上,只需要一個Redis,然后一個Mysql和一個有Maven環(huán)境的開發(fā)工具即可運行起來。

運行步驟

Github下載源碼(不定期更新和修復BUG),導入到Eclipse、MyEclipes、Idea類似開發(fā)工具。

解決編譯錯誤,修改JDK為1.7以上(請勿使用工具自帶JDK)。

在Mysql數(shù)據(jù)庫中創(chuàng)建一個數(shù)據(jù)庫,庫名隨便。

從項目/init/sql/下,先執(zhí)行tables.sql創(chuàng)建表,再運行init.data.sql插入初始化數(shù)據(jù)。

再修改配置jdbc.properties把數(shù)據(jù)庫鏈接改成您的。

安裝Redis服務,如果您沒用過,或者沒安裝,請看這里==>Redis 安裝,以及注意事項都在里面有說明。

安裝完畢后,修改配置:spring-cache.xml,如果是本地,無序修改,啟動Redis,如對Redis不了解的同學,建議別設置密碼。

運行項目,如果還有錯誤請參考異常信息,并解決,如果實在不能解決,請加QQ群交流,群需要付費5元,加群請看右側菜單。

項目帳號和線上Demo一致:管理員帳號:admin,密碼:sojson.com 如果密碼錯誤,請用 sojson

線上Demo說明

Demo已經(jīng)部署到線上,地址是:http://shiro.itboy.net

管理員帳號:admin,密碼:sojson.com 如果密碼錯誤,請用 sojson

你可以注冊自己的帳號,然后用管理員賦權限給你自己的帳號,但是,每20分鐘會把數(shù)據(jù)初始化一次。建議自己下載源碼,讓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版本出現(xiàn)的問題和BUG。

Shiro Demo 0.2版本為Shiro Demo 0.1的升級版本

PS:請選用0.2版本,這樣你遇到的問題會比較少。

升級內(nèi)容:

修復了些許BUG,優(yōu)化了語法。

0.1版本限制較多,比如要部署到Tomcat Root下才能正常運行,就是用http://localhost:8080方式訪問。

0.2版本可以采用目錄訪問,如:http://localhost:8080/shiro.demo/,默認項目名稱為/shiro.demo/

Shiro 簡介

Apache?Shiro是Java的一個安全框架。我們經(jīng)常看到它被拿來和SpringSecurity來對比。大部分人認為ShiroSecurity要簡單。我的觀點贊成一半一半吧。

首先Shiro確實和Security是同類型的框架,主要用來做安全,也就是我們俗稱的權限校驗(控制)。居多人對Shiro的定義為好入門。

我選型為Shiro,主要的原因擴展太easy了,而且我要的功能它都有。

本教程開發(fā)環(huán)境

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

本教程開發(fā)工具是Myecilpse8.5。

本教程編碼格式為UTF-8。

本教程JDK為1.7,請勿使用自帶工具JDK。

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

Redis版本隨意。

本教程Spring版本為4.2.5。

前端頁面采用Bootstrap 3.2。

本教程包含的內(nèi)容

SSM(SpringMVC+Spring+Mybatis)框架的增刪改查(含分頁),所以如果框架小白也是可以看看的。

View層主要是Freemarker,但是為了考慮到好多人還使用的是JSP,也有一個頁面是用JSP實現(xiàn)的,并且框架支持Freemarker和JSP雙View展示(優(yōu)先找Freemarker)。

Shiro+Redis的集成,也提供Ehcache的依賴Jar。

Shiro初始權限動態(tài)加載。

Shiro自定義權限校驗Filter定義,及功能實現(xiàn)。

ShiroAjax請求權限不滿足,攔截后解決方案。

ShiroFreemarker標簽使用。

ShiroJSP標簽使用。

Shiro登錄后跳轉到最后一個訪問的頁面。

用戶禁止登錄Demo。

在線顯示,在線用戶管理(踢出登錄)。

登錄注冊密碼加密傳輸Demo(詳細請見下面講解)。

密碼修改。

用戶個人中心。

權限的增刪改查。

角色的增刪改查。

權限->角色->用戶之間的關系維護。

管理員權限的自動添加(當有一個權限創(chuàng)建,自動添加到管理員角色下,保證管理員是最大權限)。

Spring定時任務數(shù)據(jù)化數(shù)據(jù)。

集成多種驗證碼(包括動態(tài)的gif驗證碼哦)。

一個帳號多處登錄限制,踢出用戶。

后續(xù)會陸陸續(xù)續(xù)升級... ...

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

本教程是SSM(SpringMVC+Spring+ Mybatis +Freemarker+ JSP)+ Shiro + Redis 做的整體Demo,其他框架需要自己自行解決,所以不做其他框架的講解,其實是大同小異。

Controller==>Service(事務控制層) ==>Dao==>SqlMapper==>Mysql

二、View層 Freemarker,JSP

通用View層配置在spring-mvc.xml中的以【通用試圖解析器】注釋標注的區(qū)間配置。

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

Redis緩存配置主要在spring-cache.xml中。對應的所有Cache 相關Java代碼在package:com.sojson.core.shiro.cache中

四、Shiro 初始權限動態(tài)加載。

我們一般是這么加載的。在spring-shiro.xml中配置

/** = anon

/page/login.jsp = anon

/page/register/* = anon

/page/index.jsp = authc

/page/addItem* = authc,roles[數(shù)據(jù)管理員]

/page/file* = authc,roleOR[普通用戶,數(shù)據(jù)管理員]

/page/listItems* = authc,roleOR[數(shù)據(jù)管理員,普通用戶]

/page/showItem* = authc,roleOR[數(shù)據(jù)管理員,普通用戶]

/page/updateItem*=authc,roles[數(shù)據(jù)管理員]

本教程采用動態(tài)加載,你可以從數(shù)據(jù)庫里讀取然后拼接成shiro要的數(shù)據(jù)。

配置文件方式加載詳細講解:http://www.sojson.com/blog/148.html

五、Shiro 自定義權限校驗Filter定義,及功能實現(xiàn)。

Shiro Filter在package:com.sojson.core.shiro.filter,具體配置在spring-shiro.xml中。定義了5個攔截器,具體功能看代碼以及代碼注釋。

六、Shiro Ajax請求權限不滿足,攔截后解決方案。

這里有一個前提,我們知道Ajax不能做頁面redirect和forward跳轉,所以Ajax請求假如沒登錄,那么這個請求給用戶的感覺就是沒有任何反應,而用戶又不知道用戶已經(jīng)退出了。解決代碼如下:

//Java代碼,判斷如果是Ajax請求,然后并且沒登錄,那么就給予返回JSON,login_status = 300,message = 當前用戶沒有登錄!

if(ShiroFilterUtils.isAjax(request)){// ajax請求

MapresultMap=newHashMap();

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);//當前用戶沒有登錄!

}

七、Shiro Freemarker標簽使用。

Freemarker使用Shiro 標簽的介紹:http://www.sojson.com/blog/143.html

八、Shiro JSP標簽使用。

JSP使用Shiro 標簽的介紹:http://www.sojson.com/blog/144.html

九、Shiro 登錄后跳轉到最后一個訪問的頁面。

Java中就可以這樣獲取上一個地址:

//上一個瀏覽的非Ajax的地址,在登錄后,取得地址,如果不為null,那么就跳轉過去。

Stringurl=(String)request.getAttribute(WebUtils.FORWARD_REQUEST_URI_ATTRIBUTE);

//shiro也有他的方法。詳細看下面。

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

@Override

protectedbooleanonAccessDenied(ServletRequestrequest,ServletResponseresponse)

throwsException{

//保存Request和Response,登錄后可以取到

saveRequestAndRedirectToLogin(request,response);

returnBoolean.FALSE;

}

//登錄后,取到之前的Request中的一些信息。

SavedRequestsaveRequest=WebUtils.getSavedRequest(request);

saveRequest.getMethod();//之前的請求方法

saveRequest.getQueryString();//之前請求的條件

saveRequest.getRequestURI();//之前請求的路徑

saveRequest.getRequestUrl();//之前請求的全路徑

十、用戶禁止登錄Demo

這個功能其實是一個改變用戶數(shù)據(jù)庫表里的一個字段,本Demo中:1:有效,0:禁止登錄

然后踢出用戶登錄狀態(tài)。代碼詳細請查看CustomSessionManager.java類的forbidUserById(Long id, Long status)方法。

而再次登錄的話,需要再登錄,而登錄的地方限制了用戶狀態(tài)為(0:禁止登錄)的用戶登錄。

/**

* 查詢要禁用的用戶是否在線。

* @param id 用戶ID

* @param status 用戶狀態(tài)

*/

publicvoidforbidUserById(Longid,Longstatus){

//獲取所有在線用戶

for(UserOnlineBobo:getAllUser()){

LonguserId=bo.getId();

//匹配用戶ID

if(userId.equals(id)){

//獲取用戶Session

Sessionsession=shiroSessionRepository.getSession(bo.getSessionId());

//標記用戶Session

SessionStatussessionStatus=(SessionStatus)session.getAttribute(SESSION_STATUS);

//是否踢出 true:有效,false:踢出。

sessionStatus.setOnlineStatus(status.intValue()==1);

//更新Session

customShiroSessionDAO.update(session);

}

}

}

十一、在線顯示,在線用戶管理(踢出登錄)

上面的功能依賴這個功能。從Redis中獲取所有有效的Session

/**

* 獲取所有的有效Session用戶

* @return

*/

publicListgetAllUser(){

//獲取所有session

Collectionsessions=customShiroSessionDAO.getActiveSessions();

Listlist=newArrayList();

for(Sessionsession:sessions){

UserOnlineBobo=getSessionBo(session);

if(null!=bo){

list.add(bo);

}

}

returnlist;

}

踢出后,不能直接退出,要不然用戶感覺莫名其妙。所有增加了一個Filter。SimpleAuthFilter.java如果標記為踢出,會提示用戶。具體查看源碼以及配合項目的使用。

十二、登錄注冊密碼加密傳輸

這個地方好多人糾結的。比如密碼過于簡單,即使加密后也能破解。如我們把密碼:123456,加密后就是:e10adc3949ba59abbe56e057f20f883e

這個很容易被識別,導致不安全,現(xiàn)在市面上的MD5破解其實就是把常用的數(shù)字,字母進行先加密,然后對比,美其名曰破解MD5。

那怎么能讓用戶即使使用很簡單的密碼,也發(fā)現(xiàn)不了?

本Demo的實現(xiàn)方式是:MD5(登錄帳號 + “固定值” +? 密碼),把這個作為密碼,這樣,基本是不可能猜的出來。

//Java代碼。UserManager.md5Pswd(UUser user);

/**

* 加工密碼,和登錄一致。

* @param user

* @return

*/

publicstaticUUsermd5Pswd(UUseruser){

//密碼為? email + '#' + pswd,然后MD5

user.setPswd(md5Pswd(user.getEmail(),user.getPswd()));

returnuser;

}

/**

* 字符串返回值

* @param email

* @param pswd

* @return

*/

publicstaticStringmd5Pswd(Stringemail,Stringpswd){

pswd=String.format("%s#%s",email,pswd);

pswd=MathUtil.getMD5(pswd);

returnpswd;

}

//JS代碼

varpswd=MD5(username+"#"+password);

十三、密碼修改

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

十四、用戶個人中心

包含的功能有[個人資料,資料修改,密碼修改,我的權限],具體看Demo。

十五、權限的增刪改查。

本Demo的設計是遵循RBAC3的思想。http://www.sojson.com/blog/142.html

RBAC個人理解介紹:http://www.sojson.com/blog/141.html

具體實現(xiàn)看Demo。

十六、角色的增刪改查

十七、權限->角色->用戶之間的關系維護

把權限賦給角色。

把角色賦給用戶。

十八、管理員權限的自動添加

這里每次添加一個權限,都會添加到“管理員”角色下,保證“管理員”角色擁有最大權限。

十九、Spring定時任務數(shù)據(jù)初始化

這個Demo因為是開放的,所以創(chuàng)建了一個定時任務。每20分鐘執(zhí)行一次,用Mysql存儲過程重新創(chuàng)建表,重新插入初始化數(shù)據(jù)。

具體數(shù)據(jù)看項目中的init/sql下的tables.sql(初始化表),init.data.sql(初始化數(shù)據(jù))。

//定時任務配置文件spring-timer.xml

//Java 代碼 RoleServiceImpl.java

/**

* 每20分鐘執(zhí)行一次

*/

@Override

@Scheduled(cron="0 0/20 * * * ? ")

publicvoidinitData(){

roleMapper.initData();

}

二十、集成驗證碼

項目中package:com.sojson.common.utils.vcode包是驗證碼的封裝包。

并且提供了一個VerifyCodeUtils.java 的驗證碼工具類。

使用方法參見:CommonController.java類中的getVCode()方法和getGifCode()方法。

驗證碼詳細介紹、

Java生成驗證碼合集(一)簡單版、

Java生成驗證碼合集(二)GJF版。

二十一、一個帳號多處登錄限制,踢出用戶。

項目中我們會用到單點登錄,還有用到單個賬號怎么限制同時只能一個人在線?

Shiro教程(十一)Shiro 控制并發(fā)登錄人數(shù)限制實現(xiàn),登錄踢出實現(xiàn):http://www.sojson.com/blog/158.html

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容