jarvis鑒權(quán)組件

基于shiro的通用鑒權(quán)組件Jarvis

大部分應(yīng)用都有鑒權(quán)的需求。如應(yīng)用認證岩榆,要求訪問者需要登錄才能訪問窥翩。再如應(yīng)用授權(quán),不僅要求訪問者登錄项贺,還需要訪問被授予權(quán)限才能訪問特定資源君躺。

image.png

為每個大大小小應(yīng)用開發(fā)安全模塊其實是一件繁瑣的事情。每個應(yīng)用的安全模塊都提供認證和授權(quán)功能开缎。
jarvis是一個通用的spring java應(yīng)用鑒權(quán)組件棕叫,具有如下特性:

  • 組件化。需要配置的項目僅需引用組件的maven依賴奕删,提供簡單配置文件即可擁有鑒權(quán)模塊...
  • 在線化俺泣。提供在線web配置,在線管理用戶完残,角色伏钠,權(quán)限。
  • 實時化谨设。實時維護資源權(quán)限贝润,實時生效(通常項目的url資源訪問權(quán)限由配置文件進行定義,如果修改需要重啟項目)铝宵。
  • url權(quán)限粒度

Apache Shiro

什么是shiro打掘?

image.png

日語發(fā)音,中文意思是“城堡”鹏秋,是一個功能強大且容易使用的java安全框架尊蚁。提供認證,授權(quán)侣夷,加密横朋,會話管理等功能,被廣泛使用百拓。

Servlet過濾器

Filter是在Servlet 2.3之后增加的新功能琴锭,當需要限制用戶訪問某些資源或者在處理請求時提前處理某些資源的時候,就可以使用過濾器完成衙传。

image.png

image.png

shiroFilter

Shiro對Servlet容器的FilterChain進行了代理,先執(zhí)行Shiro自己的Filter鏈,再執(zhí)行Servlet容器的Filter鏈(即原始的Filter)决帖。

image.png

shiro 核心概念

Subject、SecurityManager蓖捶、Realm

image.png

Subject

表示當前正在執(zhí)行操作的用戶地回,用戶通常是人,也可以是其他應(yīng)用進程。獲取當前用戶的代碼很簡單:

import org.apache.shiro.subject.Subject;
import org.apache.shiro.SecurityUtils;
...
Subject currentUser = SecurityUtils.getSubject();

一旦獲取到當前用戶實例對象刻像,就可以進行登錄登出畅买,權(quán)限檢查等操作...

SecurityManager

Subject代表當前用戶,SecurityManager代表所有用戶细睡,是shiro框架的核心谷羞。
當Subject進行l(wèi)ogin或logout或checkPermission時,其實都是交由SecurityManager進行溜徙,SecurityManager能協(xié)調(diào)這些組件完成工作洒宝。

  • Authenticator 負責登錄驗證。獲取安全數(shù)據(jù)(通過realm)萌京,獲取當前Subject的信息,兩者比較宏浩,通過則登錄成功知残,失敗則拋出異常。
  • Authorizer 負責登錄Subject的權(quán)限校驗比庄。
  • SessionManager 創(chuàng)建求妹,維護,清除所有應(yīng)用session佳窑。
  • CacheManager 緩存管理組件制恍,shiro需要可以獲取用戶安全數(shù)據(jù)用于認證,通常這些數(shù)據(jù)不會經(jīng)常變動神凑,對這些數(shù)據(jù)做緩存可以提升框架性能净神。
  • Cryptography 加密組件,如密碼加密溉委。

通常開發(fā)者很少直接和SecurityManager進行交互...SecurityManager采用門面模式(外觀模式)鹃唯,可以當成一個容器類,包含各個安全組件瓣喊,及各個組件的get坡慌,set方法,因此也可以看成是一個java bean藻三,這種結(jié)構(gòu)的類可以很方便的進行xml配置...擴展性也強洪橘,可以配置自己實現(xiàn)的組件。SecurityManager不進行真正的Security操作棵帽,但知道何時進行并調(diào)用協(xié)調(diào)各個組件進行工作熄求。

  • Realms
Realm

realm是Shiro和應(yīng)用安全數(shù)據(jù)的“橋梁”。進行登錄或訪問控制的時候逗概,shiro需要獲取應(yīng)用的用戶抡四,角色,權(quán)限等數(shù)據(jù),shiro通過配置好的realm來獲取這些數(shù)據(jù)指巡,從這點來看淑履,realm是一個DAO
(數(shù)據(jù)訪問對象)。shiro提供了一些內(nèi)置的realm組件藻雪,用于訪問不同數(shù)據(jù)源的安全數(shù)據(jù)秘噪,如關(guān)系型數(shù)據(jù)庫,文本配置文件等勉耀。開發(fā)者也可以實現(xiàn)自己的Realm指煎,如果這些內(nèi)置的realm不滿足需求。

Jarvis基于Apache Shiro的登錄流程

  • controller接口便斥,接收登錄請求至壤,請求參數(shù)通常包含用戶名和密碼,封裝成shiro的 UsernamePasswordToken對象,獲取當前Subject枢纠,調(diào)用login(token)方法;像街,將用戶信息提交給認證authenticator組件。
@RequestMapping(value = "/login")
public String login(@Valid User user, BindingResult bindingResult, HttpServletRequest request, Map map) {
        if (bindingResult.hasErrors()) {
            return "index";
        }
        String username = user.getUsername();
        UsernamePasswordToken token = new UsernamePasswordToken(user.getUsername(), user.getPassword(), false);
        // 獲取當前的Subject
        Subject currentUser = SecurityUtils.getSubject();
        try {
            logger.info("對用戶[" + username + "]進行登錄驗證..驗證開始");
            currentUser.login(token);
            logger.info("對用戶[" + username + "]進行登錄驗證..驗證通過");
        } catch (UnknownAccountException uae) {
            logger.info("對用戶[" + username + "]進行登錄驗證..驗證未通過,未知賬戶");
.....
.....
  • authenticator組件調(diào)用自定義的realm組件doGetAuthenticationInfo(AuthenticationToken token)方法晋渺。
    其中doGetAuthenticationInfo(AuthenticationToken token)方法是登錄驗證的安全數(shù)據(jù)獲取方法镰绎,代碼邏輯如下:
  1. 根據(jù)當前Subject提供的用戶名稱查詢出用戶
  2. 用戶為null,返回null木西,subject.login(token)方法拋未知賬戶異常
  3. 如果用戶不為null畴栖,封裝成SimpleAuthenticationInfo實體對象并返回,shiro的Authentication組件會進行密碼校驗八千,校驗失敗則拋出異常B鹧取(校驗前按需進行密碼解密,這些shiro都會幫開發(fā)者完成)恋捆。
    以下是realm組件doGetAuthenticationInfo(用戶數(shù)據(jù)獲取)的實現(xiàn)
@Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken)
            throws AuthenticationException {
        // UsernamePasswordToken對象用來存放提交的登錄信息
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        logger.info("驗證當前Subject時獲取到token為:" + ReflectionToStringBuilder.toString(token, ToStringStyle.MULTI_LINE_STYLE));
        // 查出是否有此用戶
        User user = userService.findByName(token.getUsername());
        if (user != null) {
            SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user.getUsername(), // account
                    user.getPassword(), // 密碼
                    ByteSource.Util.bytes(user.getCredentialsSalt()), // username+salt
                    getName() // realm name
            );
            // 若存在关翎,將此用戶存放到登錄認證info中,無需自己做密碼對比鸠信,Shiro會為我們進行密碼對比校驗
            return info;
        }
        return null;
    }

  • 處理登錄校驗結(jié)果纵寝。shiro的authentication組件根據(jù)校驗產(chǎn)生的錯誤會拋出各種異常。
try {
            logger.info("對用戶[" + username + "]進行登錄驗證..驗證開始");
            currentUser.login(token);
            logger.info("對用戶[" + username + "]進行登錄驗證..驗證通過");
        } catch (UnknownAccountException uae) {
            logger.info("對用戶[" + username + "]進行登錄驗證..驗證未通過,未知賬戶");
            map.put("message", "未知賬戶");
        } catch (IncorrectCredentialsException ice) {
            logger.info("對用戶[" + username + "]進行登錄驗證..驗證未通過,錯誤的憑證");
            map.put("message", "密碼不正確");
        } catch (LockedAccountException lae) {
            logger.info("對用戶[" + username + "]進行登錄驗證..驗證未通過,賬戶已鎖定");
            map.put("message", "賬戶已鎖定");
        } catch (ExcessiveAttemptsException eae) {
            logger.info("對用戶[" + username + "]進行登錄驗證..驗證未通過,錯誤次數(shù)過多");
            map.put("message", "用戶名或密碼錯誤次數(shù)過多");
        } catch (AuthenticationException ae) {
            // 通過處理Shiro的運行時AuthenticationException就可以控制用戶登錄失敗或密碼錯誤時的情景
            logger.info("對用戶[" + username + "]進行登錄驗證..驗證未通過,堆棧軌跡如下");
            ae.printStackTrace();
            map.put("message", "用戶名或密碼不正確");
        }

shiro權(quán)限配置

shiro權(quán)限配置一般是這樣的:
告訴shiro哪些資源需要哪些角色或哪些權(quán)限...

<property name="filterChainDefinitions" >
    <value>
        /** = anon
        /page/login.jsp = anon
        /page/register/* = anon
        /page/index.jsp = authc
        /page/addItem* = authc,roles[數(shù)據(jù)管理員]
        /page/file* = authc,roles[普通用戶]
        /page/listItems* = authc,perms[刪除數(shù)據(jù)]
        /page/showItem* = authc,perms[添加數(shù)據(jù)]
        /page/updateItem*=authc,roles[數(shù)據(jù)管理員]
    </value>
</property>

當請求傳遞到PathMatchingFilter過濾器時星立,PathMatchingFilter根據(jù)請求url路徑解析對應(yīng)的配置(anon爽茴,authc),即mappedValue,然后調(diào)用onPreHandle(),進行權(quán)限校驗绰垂,和realm提供的安全數(shù)據(jù)比對室奏,檢查當前用戶是否擁有mappedValue所要求的權(quán)限。

boolean pathsMatch(String path, ServletRequest request)  
boolean onPreHandle(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception   

動態(tài)url權(quán)限配置

大部分shiro應(yīng)用使用配置文件配置資源權(quán)限劲装,修改配置后需要重啟才能生效胧沫。

        AbstractShiroFilter abstractShiroFilter = null;
        try {
            abstractShiroFilter = (AbstractShiroFilter)bean.getObject();
        } catch (Exception e) {
            e.printStackTrace();
        }
        // 獲取過濾管理器  
        PathMatchingFilterChainResolver filterChainResolver = (PathMatchingFilterChainResolver) abstractShiroFilter  
                .getFilterChainResolver();  
        DefaultFilterChainManager manager = (DefaultFilterChainManager) filterChainResolver.getFilterChainManager();  
        // 清空初始權(quán)限配置  
        manager.getFilterChains().clear();  
        bean.getFilterChainDefinitionMap().clear();  
        // 重新構(gòu)建生成  
        set(bean,definitions);
        Map<String, String> chains = bean.getFilterChainDefinitionMap();  
        for (Map.Entry<String, String> entry : chains.entrySet()) {  
            String url = entry.getKey();  
            String chainDefinition = entry.getValue().trim().replace(" ", "");  
            manager.createChain(url, chainDefinition);  
        }  

Jarvis基于Apache Shiro的權(quán)限控制流程

Jarvis采用用戶-角色-權(quán)限的權(quán)限控制體系昌简。
表結(jié)構(gòu)設(shè)計:
user用戶表
role角色表
permission權(quán)限表
用戶角色關(guān)系表 多對多關(guān)系
角色權(quán)限關(guān)系表 多對多關(guān)系

image.png

談?wù)劷巧?/h4>

角色是權(quán)限的集合。

隱式角色和顯式角色(implicit role和explicit role)
  • 隱式角色绒怨。使用隱式角色做權(quán)限校驗并不關(guān)心權(quán)限纯赎,僅僅關(guān)心角色本身。即能做什么事情南蹂,是因為擁有什么角色...
  • 顯式角色犬金。 能做什么事情,是因為擁有什么角色六剥,而這個角色擁有這個權(quán)限去做這件事晚顷。

Jarvis即支持隱式角色也支持顯式角色,以下是realm組件doGetAuthorizationInfo(權(quán)限安全數(shù)據(jù)獲取)的實現(xiàn):

@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        logger.info("##################執(zhí)行Shiro權(quán)限認證##################");
        String loginName = (String) super.getAvailablePrincipal(principalCollection);
        // 到數(shù)據(jù)庫查是否有此對象
        User user = userService.findByName(loginName);// 實際項目中疗疟,這里可以根據(jù)實際情況做緩存该默,如果不做,Shiro自己也是有時間間隔機制策彤,2分鐘內(nèi)不會重復(fù)執(zhí)行該方法
        if (user != null) {
            // 權(quán)限信息對象info,用來存放查出的用戶的所有的角色(role)及權(quán)限(permission)
            SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
            // 用戶的角色集合
            info.setRoles(user.getRolesName());
            // 用戶的角色對應(yīng)的所有權(quán)限栓袖,如果只使用角色定義訪問權(quán)限,下面的四行可以不要 隱式角色
            List<Role> roleList = user.getRoleList();
            for (Role role : roleList) {
                info.addStringPermissions(role.getPermissionsName());
            }
            return info;
        }
        // 返回null的話锅锨,就會導(dǎo)致任何用戶訪問被攔截的請求時,都會自動跳轉(zhuǎn)到unauthorizedUrl指定的地址
        return null;
    }

Jarvis集成超級詳情日志分析應(yīng)用

引入maven依賴

 <dependency>
    <groupId>com.hlg.bigdata</groupId>
    <artifactId>Jarvis</artifactId>
    <version>0.0.1-SNAPSHOT</version>
</dependency> 

配置文件application.properties

spring.datasource.url=jdbc:mysql://localhost:3306/cjxqlog?useUnicode=true&characterEncoding=utf8
spring.datasource.username=root
spring.datasource.password=5581653
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
#logging.path=/Users/yangwq/cjxq/
spring.jpa.database-platform=org.hibernate.dialect.MySQL5Dialect
spring.jpa.properties.hibernate.hbm2ddl.auto=update

未來可以考慮集成data-plant恋沃,商品分類系統(tǒng)等需要鑒權(quán)的應(yīng)用必搞。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市囊咏,隨后出現(xiàn)的幾起案子恕洲,更是在濱河造成了極大的恐慌,老刑警劉巖梅割,帶你破解...
    沈念sama閱讀 219,366評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異户辞,居然都是意外死亡泌类,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,521評論 3 395
  • 文/潘曉璐 我一進店門底燎,熙熙樓的掌柜王于貴愁眉苦臉地迎上來刃榨,“玉大人,你說我怎么就攤上這事双仍∈嘞#” “怎么了?”我有些...
    開封第一講書人閱讀 165,689評論 0 356
  • 文/不壞的土叔 我叫張陵朱沃,是天一觀的道長苞轿。 經(jīng)常有香客問我茅诱,道長,這世上最難降的妖魔是什么搬卒? 我笑而不...
    開封第一講書人閱讀 58,925評論 1 295
  • 正文 為了忘掉前任瑟俭,我火速辦了婚禮,結(jié)果婚禮上秀睛,老公的妹妹穿的比我還像新娘尔当。我一直安慰自己,他們只是感情好蹂安,可當我...
    茶點故事閱讀 67,942評論 6 392
  • 文/花漫 我一把揭開白布椭迎。 她就那樣靜靜地躺著,像睡著了一般田盈。 火紅的嫁衣襯著肌膚如雪畜号。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,727評論 1 305
  • 那天允瞧,我揣著相機與錄音简软,去河邊找鬼。 笑死述暂,一個胖子當著我的面吹牛痹升,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播畦韭,決...
    沈念sama閱讀 40,447評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼疼蛾,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了艺配?” 一聲冷哼從身側(cè)響起察郁,我...
    開封第一講書人閱讀 39,349評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎转唉,沒想到半個月后皮钠,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,820評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡赠法,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,990評論 3 337
  • 正文 我和宋清朗相戀三年麦轰,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片砖织。...
    茶點故事閱讀 40,127評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡原朝,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出镶苞,到底是詐尸還是另有隱情喳坠,我是刑警寧澤,帶...
    沈念sama閱讀 35,812評論 5 346
  • 正文 年R本政府宣布茂蚓,位于F島的核電站壕鹉,受9級特大地震影響剃幌,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜晾浴,卻給世界環(huán)境...
    茶點故事閱讀 41,471評論 3 331
  • 文/蒙蒙 一负乡、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧脊凰,春花似錦抖棘、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,017評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至帕胆,卻和暖如春朝捆,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背懒豹。 一陣腳步聲響...
    開封第一講書人閱讀 33,142評論 1 272
  • 我被黑心中介騙來泰國打工芙盘, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人脸秽。 一個月前我還...
    沈念sama閱讀 48,388評論 3 373
  • 正文 我出身青樓儒老,卻偏偏與公主長得像,于是被迫代替她去往敵國和親记餐。 傳聞我的和親對象是個殘疾皇子驮樊,可洞房花燭夜當晚...
    茶點故事閱讀 45,066評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 前言 Spring boot 是什么,網(wǎng)上的很多介紹剥扣,這里博客就不多介紹了巩剖。如果不明白Spring boot是什么...
    xuezhijian閱讀 17,911評論 13 39
  • 文章轉(zhuǎn)載自:http://blog.csdn.net/w1196726224/article/details/53...
    wangzaiplus閱讀 3,399評論 0 3
  • 構(gòu)建一個互聯(lián)網(wǎng)應(yīng)用铝穷,權(quán)限校驗管理是很重要的安全措施钠怯,這其中主要包含: 認證 - 用戶身份識別,即登錄 授權(quán) - 訪...
    zhuke閱讀 3,510評論 0 30
  • Apache Shiro Apache Shiro 是一個強大而靈活的開源安全框架曙聂,它干凈利落地處理身份認證晦炊,授權(quán)...
    羅志贇閱讀 3,228評論 1 49
  • (高中畢業(yè)那年,你走之后宁脊,風都靜止了) 風吹來了傷悲 月從此流淚 忘了你發(fā)光的面 只留我殘碎的心 今天不會再次出現(xiàn)...
    漫步1閱讀 176評論 0 1