shiro在項(xiàng)目中的使用(一)

【前言】
Apache Shiro是Java的一個(gè)安全框架。主要用于權(quán)限控制,簡(jiǎn)單易用妇斤。之前單看shiro始終理會(huì)不了它的思想,后來在網(wǎng)上發(fā)現(xiàn)某智的一個(gè)bos項(xiàng)目中運(yùn)用到了shiro,果斷學(xué)習(xí)站超,看完后略有心得荸恕,以記之。

【項(xiàng)目簡(jiǎn)介】
該bos項(xiàng)目主要是一個(gè)后臺(tái)管理項(xiàng)目死相,采用傳統(tǒng)ssh技術(shù)架構(gòu)融求,使用spring與shiro進(jìn)行整合做權(quán)限攔截,以下是項(xiàng)目中權(quán)限部分的筆記算撮。

首先生宛,我們從外部來看Shiro吧,即從應(yīng)用程序角度的來觀察如何使用Shiro完成工作

shiro工作流程.png
Subject:主體肮柜,代表了當(dāng)前“用戶”

SecurityManager:安全管理器陷舅;即所有與安全有關(guān)的操作都會(huì)與SecurityManager交互

Realm:域,Shiro從從Realm獲取安全數(shù)據(jù)(如用戶审洞、角色莱睁、權(quán)限)

用戶主體訪問系統(tǒng),由安全管理器進(jìn)行權(quán)限驗(yàn)證芒澜,安全管理器從Realm域中獲取到該用戶的角色權(quán)限仰剿,并作出相應(yīng)的權(quán)限反饋,Realm域就是一個(gè)Dao痴晦,主要獲取用戶的角色權(quán)限數(shù)據(jù)并交給安全管理器南吮。所以整個(gè)流程中,安全管理器是核心角色誊酌。

【1】web.xml中配置shiro的過濾器
shiro的過濾器就類似于struts2的核心過濾器一般

<!-- shiro過濾器 -->
    <filter>
        <filter-name>shiroFilter</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>shiroFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

注意:這里filterName的值可以隨便起部凑,無要求。但是在spring注入時(shí)要保持一致

【2】將shiro過濾器注入spring

<!-- 配置工廠bean术辐,用于創(chuàng)建shiro框架用到過濾器 -->
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <!-- 注入安全管理 -->
        <property name="securityManager" ref="securityManager"></property>
        <!-- 注入當(dāng)前系統(tǒng)的登錄頁面 -->
        <property name="loginUrl" value="/login.jsp"></property>
        <!-- 注入成功頁面 -->
        <property name="successUrl" value="/index.jsp"></property>
        <!-- 注入權(quán)限不足頁面 -->
        <property name="unauthorizedUrl" value="/unauthorizedUrl.jsp"/>
        <!-- 注入url攔截規(guī)則 -->
        <property name="filterChainDefinitions">
            <value>
                /css/** = anon
                /images/** = anon
                /js/** = anon
                /login.jsp* = anon
                /validatecode.jsp* = anon
                /userAction_login.action = anon
                /page_base_staff.action = perms["staff"]<!-- roles角色集,perms權(quán)限集 -->
                /* = authc
            </value>
            <!-- 
                /page_base_staff.action = roles["staff"]//要訪問此action必須有staff這個(gè)角色
                /page_base_staff.action = perms["staff"]//要訪問此action必須有staff這個(gè)權(quán)限
             -->
        </property>
    </bean>

注意:以上屬性均以set注入砚尽,查看ShiroFilterFactoryBean源碼便知,業(yè)務(wù)需要配哪個(gè)屬性就配哪個(gè)辉词,非必要配置必孤,這里頁面以/開頭均在webroot目錄下。

這里bean 的id屬性要與web.xml中shiro的過濾器名稱一致

url攔截規(guī)則:一般圖片瑞躺、JS敷搪、CSS樣式不攔截,直接設(shè)置anon角色權(quán)限即可(/css/** = anon)
具體url攔截:
    /page_base_staff.action = perms["staff"]//訪問此action需要staff權(quán)限
    /page_base_staff.action =roles["staff"]//訪問此action需要staff角色(角色是權(quán)限的集合)

要攔截的路徑:/* = authc

【3】編寫自定義Realm域并注入到spring中
自定義Realm需要繼承AuthorizingRealm幢哨,實(shí)現(xiàn)其認(rèn)證 授權(quán)方法

/**
 * ClassName: BOSRealm
 * @author lvfang
 * @Desc: 自定義realm
 * @date 2017-8-23
 */
public class BOSRealm extends AuthorizingRealm {
    
    @Resource
    private IUserDao userDao;
    
    /**
     * 認(rèn)證方法(是否有這個(gè)用戶)
     */
    protected AuthenticationInfo doGetAuthenticationInfo(
            AuthenticationToken token) throws AuthenticationException {
        System.out.println("進(jìn)入認(rèn)證方法... ...");
        UsernamePasswordToken upToken = (UsernamePasswordToken) token;//token令牌強(qiáng)轉(zhuǎn)
        String username = upToken.getUsername();//從令牌中得到用戶名
        
        //查詢用戶
        User user = userDao.findUserByUsername(username);
        if(user == null){
            //用戶名不存在
            return null;
        }else{
            //用戶名存在
            String password = user.getPassword();
            
            // 創(chuàng)建簡(jiǎn)單認(rèn)證信息對(duì)象
            /***
             * 參數(shù)一:簽名赡勘,程序可以在任意位置獲取當(dāng)前放入的對(duì)象
             * 參數(shù)二:從數(shù)據(jù)庫(kù)中查詢出的密碼
             * 參數(shù)三:當(dāng)前realm的名稱
             */
            SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user,password,this.getClass().getSimpleName());
            //返回給安全管理器,由安全管理器負(fù)責(zé)比對(duì)數(shù)據(jù)庫(kù)中查詢出的密碼和頁面提交的密碼
            return info;
        }   
    }

    /**
     * 授權(quán)方法(這個(gè)用戶有什么權(quán)限)
     */
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        System.out.println("進(jìn)入授權(quán)方法... ...");
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        info.addStringPermission("staff");//為當(dāng)前用戶授予staff權(quán)限
        info.addRole("staff");//為當(dāng)前用戶授予staff角色(角色是權(quán)限的集合)    
        //TODO 根據(jù)當(dāng)前登錄用戶查詢數(shù)據(jù)庫(kù)捞镰,獲取其對(duì)應(yīng)的權(quán)限數(shù)據(jù)
        
        return info;
    }
}

注入spring

<!-- 注冊(cè)自定義realm -->
    <bean id="bosRealm" class="com.itheima.bos.shiro.BOSRealm"></bean>

【4】注入安全管理器闸与,并將realm注入給安全管理器

<!-- 注入 securityManager管理器-->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <!-- 將自定義realm注入給securityManager管理 -->
        <property name="realm" ref="bosRealm"></property>
    </bean>

【5】在login方法中做處理

/**
     * 登陸方法(shiro版)
     * @return
     */
    public String login(){  
        //判斷驗(yàn)證碼
        String code = (String) this.setSession("key");
        //判斷驗(yàn)證碼是否正確
        if(StringUtils.isNotBlank(checkcode)&& checkcode.equals(code)){
            
            //獲取當(dāng)前用戶對(duì)象
            Subject subject = SecurityUtils.getSubject();//目前為"未認(rèn)證狀態(tài)"
            String password = model.getPassword();
            password = MD5Utils.md5(password);
            //構(gòu)造一個(gè)用戶名密碼令牌
            AuthenticationToken token = new UsernamePasswordToken(model.getUsername(),password);
            
            try {
                subject.login(token);
            } catch (UnknownAccountException e) {
                e.printStackTrace();
                //登陸失敗  設(shè)置提示信息毙替,跳轉(zhuǎn)登陸頁面
                this.addActionError("用戶名不存在!");
                return "login";
            } catch (Exception e) {
                e.printStackTrace();
                //登陸失敗  設(shè)置提示信息践樱,跳轉(zhuǎn)登陸頁面
                this.addActionError("用戶名或密碼錯(cuò)誤厂画!");
                return "login";
            }
            
            //獲取認(rèn)證信息對(duì)象中存儲(chǔ)的User對(duì)象
            User user = (User) subject.getPrincipal();
            this.getSession().setAttribute("loginUser", user);//用戶存入session
            return "home";
        }else{
            //登陸失敗,驗(yàn)證碼失敗 跳轉(zhuǎn)至登陸頁面
            this.addActionError("驗(yàn)證碼錯(cuò)誤拷邢!");
            return "login";
        }   
    }

這里根據(jù)username和password構(gòu)造一個(gè)用戶名令牌袱院,當(dāng)subject主體去調(diào)用login()方法登陸時(shí),會(huì)執(zhí)行Realm域中的認(rèn)證和授權(quán)方法瞭稼。

【附加】

1:
shiro過濾器屬性含義

securityManager:這個(gè)屬性是必須的忽洛。

loginUrl :沒有登錄的用戶請(qǐng)求需要登錄的頁面時(shí)自動(dòng)跳轉(zhuǎn)到登錄頁面,不是必須的屬性环肘,不輸入地址的話會(huì)自動(dòng)尋找項(xiàng)目web項(xiàng)目的根目錄下的”/login.jsp”頁面欲虚。

successUrl :登錄成功默認(rèn)跳轉(zhuǎn)頁面,不配置則跳轉(zhuǎn)至”/”廷臼。如果登陸前點(diǎn)擊的一個(gè)需要登錄的頁面苍在,則在登錄自動(dòng)跳轉(zhuǎn)到那個(gè)需要登錄的頁面绝页。不跳轉(zhuǎn)到此荠商。

unauthorizedUrl :沒有權(quán)限默認(rèn)跳轉(zhuǎn)的頁面


2:
其權(quán)限過濾器及配置釋義

anon:例子/admins/**=anon 沒有參數(shù),表示可以匿名使用续誉。

authc:例如/admins/user/**=authc表示需要認(rèn)證(登錄)才能使用莱没,沒有參數(shù)

roles(角色):例子/admins/user/**=roles[admin],參數(shù)可以寫多個(gè),多個(gè)時(shí)必須加上引號(hào)酷鸦,并且參數(shù)之間用逗號(hào)分割饰躲,當(dāng)有多個(gè)參數(shù)時(shí),例如admins/user/**=roles["admin,guest"],每個(gè)參數(shù)通過才算通過臼隔,相當(dāng)于hasAllRoles()方法嘹裂。

perms(權(quán)限):例子/admins/user/**=perms[user:add:*],參數(shù)可以寫多個(gè),多個(gè)時(shí)必須加上引號(hào)摔握,并且參數(shù)之間用逗號(hào)分割寄狼,例如/admins/user/**=perms["user:add:*,user:modify:*"],當(dāng)有多個(gè)參數(shù)時(shí)必須每個(gè)參數(shù)都通過才通過氨淌,想當(dāng)于isPermitedAll()方法泊愧。

rest:例子/admins/user/**=rest[user],根據(jù)請(qǐng)求的方法,相當(dāng)于/admins/user/**=perms[user:method] ,其中method為post盛正,get删咱,delete等。

port:例子/admins/user/**=port[8081],當(dāng)請(qǐng)求的url的端口不是8081是跳轉(zhuǎn)到schemal://serverName:8081?queryString,其中schmal是協(xié)議http或https等豪筝,serverName是你訪問的host,8081是url配置里port的端口痰滋,queryString

是你訪問的url里的摘能?后面的參數(shù)。

authcBasic:例如/admins/user/**=authcBasic沒有參數(shù)表示httpBasic認(rèn)證

ssl:例子/admins/user/**=ssl沒有參數(shù)敲街,表示安全的url請(qǐng)求徊哑,協(xié)議為https

user:例如/admins/user/**=user沒有參數(shù)表示必須存在用戶,當(dāng)?shù)侨氩僮鲿r(shí)不做檢查

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末聪富,一起剝皮案震驚了整個(gè)濱河市莺丑,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌墩蔓,老刑警劉巖梢莽,帶你破解...
    沈念sama閱讀 222,807評(píng)論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異奸披,居然都是意外死亡昏名,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,284評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門阵面,熙熙樓的掌柜王于貴愁眉苦臉地迎上來轻局,“玉大人,你說我怎么就攤上這事样刷÷仄耍” “怎么了?”我有些...
    開封第一講書人閱讀 169,589評(píng)論 0 363
  • 文/不壞的土叔 我叫張陵置鼻,是天一觀的道長(zhǎng)镇饮。 經(jīng)常有香客問我,道長(zhǎng)箕母,這世上最難降的妖魔是什么储藐? 我笑而不...
    開封第一講書人閱讀 60,188評(píng)論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮嘶是,結(jié)果婚禮上钙勃,老公的妹妹穿的比我還像新娘。我一直安慰自己聂喇,他們只是感情好辖源,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,185評(píng)論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著授帕,像睡著了一般同木。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上跛十,一...
    開封第一講書人閱讀 52,785評(píng)論 1 314
  • 那天彤路,我揣著相機(jī)與錄音,去河邊找鬼芥映。 笑死洲尊,一個(gè)胖子當(dāng)著我的面吹牛远豺,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播坞嘀,決...
    沈念sama閱讀 41,220評(píng)論 3 423
  • 文/蒼蘭香墨 我猛地睜開眼躯护,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了丽涩?” 一聲冷哼從身側(cè)響起棺滞,我...
    開封第一講書人閱讀 40,167評(píng)論 0 277
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎矢渊,沒想到半個(gè)月后继准,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,698評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡矮男,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,767評(píng)論 3 343
  • 正文 我和宋清朗相戀三年移必,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片毡鉴。...
    茶點(diǎn)故事閱讀 40,912評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡恢氯,死狀恐怖肄方,靈堂內(nèi)的尸體忽然破棺而出悠就,到底是詐尸還是另有隱情好乐,我是刑警寧澤赶站,帶...
    沈念sama閱讀 36,572評(píng)論 5 351
  • 正文 年R本政府宣布过吻,位于F島的核電站吏砂,受9級(jí)特大地震影響城瞎,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜甘晤,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,254評(píng)論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望饲做。 院中可真熱鬧线婚,春花似錦、人聲如沸盆均。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,746評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽泪姨。三九已至游沿,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間肮砾,已是汗流浹背诀黍。 一陣腳步聲響...
    開封第一講書人閱讀 33,859評(píng)論 1 274
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留仗处,地道東北人眯勾。 一個(gè)月前我還...
    沈念sama閱讀 49,359評(píng)論 3 379
  • 正文 我出身青樓枣宫,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親吃环。 傳聞我的和親對(duì)象是個(gè)殘疾皇子也颤,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,922評(píng)論 2 361

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

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)郁轻,斷路器翅娶,智...
    卡卡羅2017閱讀 134,716評(píng)論 18 139
  • 前言 Spring boot 是什么,網(wǎng)上的很多介紹好唯,這里博客就不多介紹了故觅。如果不明白Spring boot是什么...
    xuezhijian閱讀 17,923評(píng)論 13 39
  • 1.簡(jiǎn)介 Apache Shiro是Java的一個(gè)安全框架。功能強(qiáng)大渠啊,使用簡(jiǎn)單的Java安全框架输吏,它為開發(fā)人員提供...
    H_Man閱讀 3,171評(píng)論 4 48
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,867評(píng)論 6 342
  • 雨突然 下得好猛 他沒帶傘 躲在路邊屋檐 發(fā)呆 那傘下的姑娘們 行色勿勿 他問 白娘子呀 你眼淚漣漣找啥呢 許仙又...
    雪莉詩(shī)話閱讀 157評(píng)論 1 12