1. 程式人生 > 實用技巧 >shiro 框架基本講解【轉載】

shiro 框架基本講解【轉載】

shiro 框架基本講解【轉載】

什麼是許可權管理:

      • 基本上涉及到使用者參與的系統都要進行許可權管理,許可權管理屬於系統安全的範疇,許可權管理實現對使用者訪問系統的控制,按照安全規則或者安全策略控制使用者可以訪問而且只能訪問自己被授權的資源。
      • 許可權管理包括使用者身份認證和授權兩部分,簡稱認證授權。對於需要訪問控制的資源使用者首先經過身份認證,認證通過後使用者具有該資源的訪問許可權訪問

使用者身份認證:

      • 身份認證,就是判斷一個使用者是否為合法使用者的處理過程。最常用的簡單身份認證方式是系統通過核對使用者輸入的使用者名稱和口令,看其是否與系統中儲存的該使用者的使用者名稱和口令一致,來判斷使用者身份是否正確。對於採用
        指紋
        等系統,則出示指紋;對於硬體Key等刷卡系統,則需要刷卡

使用者名稱密碼身份認證流程:

關鍵物件:

上邊的流程圖中需要理解以下關鍵物件:

Subject:主體:訪問系統的使用者,主體可以是使用者、程式等,進行認證的都稱為主體;

Principal:身份資訊:是主體(subject)進行身份認證的標識,標識必須具有唯一性,如使用者名稱、手機號、郵箱地址等,一個主體可以有多個身份,但是必須有一個主身份(Primary Principal)。

credential:憑證資訊:是隻有主體自己知道的安全資訊,如密碼、證書等。

授權:

授權,即訪問控制,控制誰能訪問哪些資源。主體進行身份認證後需要分配許可權方可訪問系統的資源,對於某些資源沒有許可權是無法訪問的

授權流程:

關鍵物件:

授權可簡單理解為who對what(which)進行How操作

ho:即主體(Subject),主體需要訪問系統中的資源。

What:即資源(Resource),如系統選單、頁面、按鈕、類方法、系統商品資訊等。資源包括資源型別和資源例項,比如商品資訊為資源型別,型別為t01的商品為資源例項,編號為001的商品資訊也屬於資源例項。

How:許可權/許可(Permission),規定了主體對資源的操作許可,許可權離開資源沒有意義,如使用者查詢許可權、使用者新增許可權、某個類方法的呼叫許可權、編號為001使用者的修改許可權等,通過許可權可知主體對哪些資源都有哪些操作許可。許可權分為粗顆粒和細顆粒,粗顆粒許可權是指對資源型別的許可權,細顆粒許可權是對資源例項的許可權。

主體、資源、許可權關係如下圖:

許可權模型:

對上節中的主體、資源、許可權通過資料模型表示:

主體(賬號、密碼)、資源(資源名稱、訪問地址)、許可權(許可權名稱、資源id)、角色(角色名稱)、角色和許可權關係(角色id、許可權id)、主體和角色關係(主體id、角色id)

如下圖:

許可權分配:

對主體分配許可權,主體只允許在許可權範圍內對資源進行操作,比如:對u01使用者分配商品修改許可權,u01使用者只能對商品進行修改。

通常需要持久化,根據上邊的資料模型建立表並將使用者的許可權資訊儲存在資料庫中

許可權控制:

使用者擁有了許可權即可操作許可權範圍內的資源,系統不知道主體是否具有訪問許可權需要對使用者的訪問進行控制

以上是對許可權的基本講解。下面開始真正的學習shiro

shiro介紹

什麼是shiro

Shiro是apache旗下一個開源框架,它將軟體系統的安全認證相關的功能抽取出來,實現使用者身份認證,許可權授權、加密、會話管理等功能,組成了一個通用的安全認證框架。

為什麼要學shiro

既然shiro將安全認證相關的功能抽取出來組成一個框架,使用shiro就可以非常快速的完成認證、授權等功能的開發,降低系統成本。
shiro使用廣泛,shiro可以執行在web應用,非web應用,叢集分散式應用中越來越多的使用者開始使用shiro。
java領域中spring security(原名Acegi)也是一個開源的許可權管理框架,但是spring security依賴spring執行,而shiro就相對獨立,最主要是因為shiro使用簡單、靈活,所以現在越來越多的使用者選擇shiro。

shiro 的架構:

subject :

Subject即主體,外部應用與subject進行互動,subject記錄了當前操作使用者,將使用者的概念理解為當前操作的主體,可能是一個通過瀏覽器請求的使用者,也可能是一個執行的程式。        
Subject在shiro中是一個介面,介面中定義了很多認證授相關的方法,外部程式通過subject進行認證授,而subject是通過SecurityManager安全管理器進行認證授權

SecurityManager:

SecurityManager即安全管理器,對全部的subject進行安全管理,它是shiro的核心,負責對所有的subject進行安全管理。通過SecurityManager可以完成subject的認證、授權等,
實SecurityManager是通過Authenticator進行認證,通過Authorizer進行授權,通過SessionManager進行會話管理等。SecurityManager是一個介面,繼承了Authenticator, Authorizer, 
SessionManager這三個介面。

Authenticator:

Authenticator即認證器,對使用者身份進行認證,Authenticator是一個介面,shiro提供 ModularRealmAuthenticator實現類,通過ModularRealmAuthenticator基本上可以滿足大多數需求,也可以自定義認證器。

Authorizer :

Authorizer即授權器,使用者通過認證器認證通過,在訪問功能時需要通過授權器判斷使用者是否有此功能的操作許可權。

realm :

Realm即領域,相當於datasource資料來源,securityManager進行安全認證需要通過Realm獲取使用者許可權資料,比如:如果使用者身份資料在資料庫那麼realm就需要從資料庫獲取使用者身份資訊。
注意:不要把realm理解成只是從資料來源取資料,在realm中還有認證授權校驗的相關的程式碼。 

sessionManager :

sessionManager即會話管理,shiro框架定義了一套會話管理,它不依賴web容器的session,所以shiro可以使用在非web應用上,也可以將分散式應用的會話集中在一點管理,此特性可使它實現單點登入。

SessionDAO :

SessionDAO即會話dao,是對session會話操作的一套介面,比如要將session儲存到資料庫,可以通過jdbc將會話儲存到資料庫。

CacheManager :

CacheManager即快取管理,將使用者許可權資料儲存在快取,這樣可以提高效能。

Cryptography :

Cryptography即密碼管理,shiro提供了一套加密/解密的元件,方便開發。比如提供常用的雜湊、加/解密等功能。

  shiro的jar包 :

<dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-core</artifactId>
            <version>1.2.3</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-web</artifactId>
            <version>1.2.3</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.2.3</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-ehcache</artifactId>
            <version>1.2.3</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-quartz</artifactId>
            <version>1.2.3</version>
        </dependency>

也可以通過引入shiro-all包括shiro所有的包:

<dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-all</artifactId>
            <version>1.2.3</version>
        </dependency>

shiro認證

認證流程:

入門程式:

1、建立普通的java 工程專案

2、匯入jar 包

3、使用log4j.properties日誌配置檔案輸出日誌

log4j.rootLogger=debug, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m %n

4、使用shiro.ini 檔案 【通過Shiro.ini配置檔案初始化SecurityManager環境】

配置 eclipse支援ini檔案編輯:

在eclipse配置後,在classpath建立shiro.ini配置檔案,為了方便測試將使用者名稱和密碼配置的shiro.ini配置檔案中:

[users]
zhang=123
lisi=123

認證程式碼:

     // 使用者登陸、使用者退出
    @Test
    public void testLoginLogout() {
        // 構建SecurityManager工廠,IniSecurityManagerFactory可以從ini檔案中初始化SecurityManager環境
        Factory<SecurityManager> factory = new IniSecurityManagerFactory(
                "classpath:shiro.ini");
        // 通過工廠建立SecurityManager
        SecurityManager securityManager = factory.getInstance();     
        // 將securityManager設定到執行環境中
        SecurityUtils.setSecurityManager(securityManager);
        // 建立一個Subject例項,該例項認證要使用上邊建立的securityManager進行
        Subject subject = SecurityUtils.getSubject();
        // 建立token令牌,記錄使用者認證的身份和憑證即賬號和密碼 
        UsernamePasswordToken token = new UsernamePasswordToken("zhang", "123");
        try {
            // 使用者登陸
            subject.login(token);
        } catch (AuthenticationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        // 使用者認證狀態
        Boolean isAuthenticated = subject.isAuthenticated();
        System.out.println("使用者認證狀態:" + isAuthenticated);

        // 使用者退出
        subject.logout();
        isAuthenticated = subject.isAuthenticated();
        System.out.println("使用者認證狀態:" + isAuthenticated);
    }

認證執行流程 :

1、 建立token令牌,token中有使用者提交的認證資訊即賬號和密碼

2、 執行subject.login(token),最終由securityManager通過Authenticator進行認證

3、 Authenticator的實現ModularRealmAuthenticator呼叫realm從ini配置檔案取使用者真實的賬號和密碼,這裡使用的是IniRealm(shiro自帶)

4、 IniRealm先根據token中的賬號去ini中找該賬號,如果找不到則給ModularRealmAuthenticator返回null,如果找到則匹配密碼,匹配密碼成功則認證通過。

以上程式使用的是Shiro自帶的IniRealm,IniRealm從ini配置檔案中讀取使用者的資訊,大部分情況下需要從系統的資料庫中讀取使用者資訊,所以需要自定義realm

shiro提供的realm 如下圖:

最基礎的是Realm介面,CachingRealm負責快取處理,AuthenticationRealm負責認證,AuthorizingRealm負責授權,通常自定義的realm繼承AuthorizingRealm

自定義Realm 程式碼如下:

public class CustomRealm1 extends AuthorizingRealm {

    @Override
    public String getName() {
        return "customRealm1";
    }

    //支援UsernamePasswordToken
    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof UsernamePasswordToken;
    }

    //認證
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(
            AuthenticationToken token) throws AuthenticationException {
        
        //從token中 獲取使用者身份資訊
        String username = (String) token.getPrincipal();
        //拿username從資料庫中查詢
        //....
        //如果查詢不到則返回null
        if(!username.equals("zhang")){//這裡模擬查詢不到
            return null;
        }
        
        //獲取從資料庫查詢出來的使用者密碼 
        String password = "123";//這裡使用靜態資料模擬。。
        
        //返回認證資訊由父類AuthenticatingRealm進行認證
        SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(
                username, password, getName());

        return simpleAuthenticationInfo;
    }

    //授權
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(
            PrincipalCollection principals) {
        // TODO Auto-generated method stub
        return null;
    }
}

同時需要建立shiro-realm.ini 檔案:

[main]
#自定義 realm
customRealm=cn.itcast.shiro.authentication.realm.CustomRealm1
#將realm設定到securityManager
securityManager.realms=$customRealm

測試程式碼同入門程式,將ini的地址修改為shiro-realm.ini

一般來說密碼需要 加密 可以選擇MD5加密方式這裡就不詳細說明。

shiro授權

授權流程 圖:

授權方式 :

Shiro 支援三種方式的授權:
    程式設計式:通過寫if/else 授權程式碼塊完成:
Subject subject = SecurityUtils.getSubject();
if(subject.hasRole(“admin”)) {
//有許可權
} else {
//無許可權
}
    註解式:通過在執行的Java方法上放置相應的註解完成:
@RequiresRoles("admin")
public void hello() {
//有許可權
}
    JSP/GSP 標籤:在JSP/GSP 頁面通過相應的標籤完成:
<shiro:hasRole name="admin">
<!— 有許可權—>
</shiro:hasRole>

授權測試 :

1、建立存放許可權的配置檔案shiro-permission.ini,如下:

[users]
#使用者zhang的密碼是123,此使用者具有role1和role2兩個角色
zhang=123,role1,role2
wang=123,role2

[roles]
#角色role1對資源user擁有create、update許可權
role1=user:create,user:update
#角色role2對資源user擁有create、delete許可權
role2=user:create,user:delete
#角色role3對資源user擁有create許可權
role3=user:create

注意:在ini檔案中使用者、角色、許可權的配置規則是:“使用者名稱=密碼,角色1,角色2...” “角色=許可權1,許可權2...”,首先根據使用者名稱找角色,再根據角色找許可權,角色是許可權集合

許可權字串規則:

許可權字串的規則是:“資源識別符號:操作:資源例項識別符號”,意思是對哪個資源的哪個例項具有什麼操作,“:”是資源/操作/例項的分割符,許可權字串也可以使用*萬用字元。

例子:
使用者建立許可權:user:create,或user:create:*
使用者修改例項001的許可權:user:update:001
使用者例項001的所有許可權:user:*:001

測試程式碼如下:

@Test
    public void testPermission() {

        // 從ini檔案中建立SecurityManager工廠
        Factory<SecurityManager> factory = new IniSecurityManagerFactory(
                "classpath:shiro-permission.ini");

        // 建立SecurityManager
        SecurityManager securityManager = factory.getInstance();

        // 將securityManager設定到執行環境
        SecurityUtils.setSecurityManager(securityManager);

        // 建立主體物件
        Subject subject = SecurityUtils.getSubject();

        // 對主體物件進行認證
        // 使用者登陸
        // 設定使用者認證的身份(principals)和憑證(credentials)
        UsernamePasswordToken token = new UsernamePasswordToken("zhang", "123");
        try {
            subject.login(token);
        } catch (AuthenticationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        // 使用者認證狀態
        Boolean isAuthenticated = subject.isAuthenticated();

        System.out.println("使用者認證狀態:" + isAuthenticated);

        // 使用者授權檢測 基於角色授權
        // 是否有某一個角色
        System.out.println("使用者是否擁有一個角色:" + subject.hasRole("role1"));
        // 是否有多個角色
        System.out.println("使用者是否擁有多個角色:" + subject.hasAllRoles(Arrays.asList("role1", "role2")));
        
//        subject.checkRole("role1");
//        subject.checkRoles(Arrays.asList("role1", "role2"));

        // 授權檢測,失敗則丟擲異常
        // subject.checkRole("role22");

        // 基於資源授權
        System.out.println("是否擁有某一個許可權:" + subject.isPermitted("user:delete"));
        System.out.println("是否擁有多個許可權:" + subject.isPermittedAll("user:create:1",    "user:delete"));
        
        //檢查許可權
        subject.checkPermission("sys:user:delete");
        subject.checkPermissions("user:create:1","user:delete");
        

    }

注意:測試程式碼同認證程式碼,注意ini地址改為shiro-permission.ini,主要學習下邊授權的方法;在使用者認證通過後執行下邊的授權程式碼

基於角色的授權:

     // 使用者授權檢測 基於角色授權
     // 是否有某一個角色
     System.out.println("使用者是否擁有一個角色:" + subject.hasRole("role1"));
     // 是否有多個角色
     System.out.println("使用者是否擁有多個角色:" + subject.hasAllRoles(Arrays.asList("role1", "role2")));

//對應的check方法:
subject.checkRole("role1");
subject.checkRoles(Arrays.asList("role1", "role2"));

上邊check方法如果授權失敗則丟擲異常:

org.apache.shiro.authz.UnauthorizedException: Subject does not have role [.....]

基於資源授權:

// 基於資源授權
        System.out.println("是否擁有某一個許可權:" + subject.isPermitted("user:delete"));
        System.out.println("是否擁有多個許可權:" + subject.isPermittedAll("user:create:1",    "user:delete"));
對應的check方法:
subject.checkPermission("sys:user:delete");
subject.checkPermissions("user:create:1","user:delete");

與上邊認證自定義realm一樣,大部分情況是要從資料庫獲取許可權資料,這裡直接實現基於資源的授權

授權自定義 realm 程式碼 如下:

直接在認證寫的自定義realm類中完善doGetAuthorizationInfo方法,此方法需要完成:根據使用者身份資訊從資料庫查詢許可權字串,由shiro進行授權:

// 授權
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(
            PrincipalCollection principals) {
        // 獲取身份資訊
        String username = (String) principals.getPrimaryPrincipal();
        // 根據身份資訊從資料庫中查詢許可權資料
        //....這裡使用靜態資料模擬
        List<String> permissions = new ArrayList<String>();
        permissions.add("user:create");
        permissions.add("user.delete");
        
        //將許可權資訊封閉為AuthorizationInfo
        
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        for(String permission:permissions){
            simpleAuthorizationInfo.addStringPermission(permission);
        }
        
        return simpleAuthorizationInfo;
    }

授權執行流程:

1、 執行subject.isPermitted("user:create")

2、 securityManager通過ModularRealmAuthorizer進行授權

3、 ModularRealmAuthorizer呼叫realm獲取許可權資訊

4、 ModularRealmAuthorizer再通過permissionResolver解析許可權字串,校驗是否匹配

shiro與spring web專案的整合

1、web.xml新增shiro Filter

<!-- shiro過慮器,DelegatingFilterProx會從spring容器中找shiroFilter -->
    <filter>
    <filter-name>shiroFilter</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
        <init-param>
            <param-name>targetFilterLifecycle</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>shiroFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

2、applicationContext-shiro.xml

<!-- Shiro 的Web過濾器 -->
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <property name="securityManager" ref="securityManager" />
        <!-- 如果沒有認證將要跳轉的登陸地址,http可訪問的url,如果不在表單認證過慮器FormAuthenticationFilter中指定此地址就為身份認證地址 -->
        <property name="loginUrl" value="/login.action" />
<!-- 沒有許可權跳轉的地址 -->
        <property name="unauthorizedUrl" value="/refuse.jsp" />
<!-- shiro攔截器配置 -->
        <property name="filters">
            <map>
                <entry key="authc" value-ref="formAuthenticationFilter" />
            </map>
        </property>
        <property name="filterChainDefinitions">
            <value>
                <!-- 必須通過身份認證方可訪問,身份認 證的url必須和過慮器中指定的loginUrl一致 -->
                /loginsubmit.action = authc
                <!-- 退出攔截,請求logout.action執行退出操作 -->
                /logout.action = logout
                <!-- 無權訪問頁面 -->
                /refuse.jsp = anon
                <!-- roles[XX]表示有XX角色才可訪問 -->
                /item/list.action = roles[item],authc
                /js/** anon
                /images/** anon
                /styles/** anon
                <!-- user表示身份認證通過或通過記住我認證通過的可以訪問 -->
                /** = user
                <!-- /**放在最下邊,如果一個url有多個過慮器則多個過慮器中間用逗號分隔,如:/** = user,roles[admin] -->

            </value>
        </property>
    </bean>


    <!-- 安全管理器 -->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <property name="realm" ref="userRealm" />
        
    </bean>

    <!-- 自定義 realm -->
    <bean id="userRealm" class="cn.itcast.ssm.realm.CustomRealm1">
    </bean>
    <!-- 基於Form表單的身份驗證過濾器,不配置將也會註冊此過慮器,表單中的使用者賬號、密碼及loginurl將採用預設值,建議配置 -->
    <bean id="formAuthenticationFilter"
        class="org.apache.shiro.web.filter.authc.FormAuthenticationFilter">
        <!-- 表單中賬號的input名稱 -->
        <property name="usernameParam" value="usercode" />
        <!-- 表單中密碼的input名稱 -->
        <property name="passwordParam" value="password" />
        <!-- <property name="rememberMeParam" value="rememberMe"/> -->
        <!-- loginurl:使用者登陸地址,此地址是可以http訪問的url地址 -->
        <property name="loginUrl" value="/loginsubmit.action" />
    </bean>

注意:

securityManager:這個屬性是必須的。
loginUrl:沒有登入認證的使用者請求將跳轉到此地址,不是必須的屬性,不輸入地址的話會自動尋找專案web專案的根目錄下的”/login.jsp”頁面。
unauthorizedUrl:沒有許可權預設跳轉的頁面。

3、使用shiro註解授權:

在springmvc.xml中配置shiro註解支援,可在controller方法中使用shiro註解配置許可權:

<!-- 開啟aop,對類代理 -->
    <aop:config proxy-target-class="true"></aop:config>
    <!-- 開啟shiro註解支援 -->
    <bean
        class="
org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
        <property name="securityManager" ref="securityManager" />
    </bean>

修改Controller程式碼,在方法上新增授權註解,如下:

// 查詢商品列表
    @RequestMapping("/queryItem")
    @RequiresPermissions("item:query")
    public ModelAndView queryItem() throws Exception {
。。。。。。。
}

上邊程式碼@RequiresPermissions("item:query")表示必須擁有“item:query”許可權方可執行

4、重新 自定義realm :

此realm先不從資料庫查詢許可權資料,當前需要先將shiro整合完成,在上定義的realm基礎上修改:

public class CustomRealm1 extends AuthorizingRealm {

    @Autowired
    private SysService sysService;

    @Override
    public String getName() {
        return "customRealm";
    }

    // 支援什麼型別的token
    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof UsernamePasswordToken;
    }

    // 認證
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(
            AuthenticationToken token) throws AuthenticationException {

        // 從token中 獲取使用者身份資訊
        String username = (String) token.getPrincipal();
        // 拿username從資料庫中查詢
        // ....
        // 如果查詢不到則返回null
        if (!username.equals("zhang")) {// 這裡模擬查詢不到
            return null;
        }

        // 獲取從資料庫查詢出來的使用者密碼
        String password = "123";// 這裡使用靜態資料模擬。。
        
        // 根據使用者id從資料庫取出選單
        //...先用靜態資料
        List<SysPermission> menus = new ArrayList<SysPermission>();;
        
        SysPermission sysPermission_1 = new SysPermission();
        sysPermission_1.setName("商品管理");
        sysPermission_1.setUrl("/item/queryItem.action");
        SysPermission sysPermission_2 = new SysPermission();
        sysPermission_2.setName("使用者管理");
        sysPermission_2.setUrl("/user/query.action");
        
        menus.add(sysPermission_1);
        menus.add(sysPermission_2);
        
        // 構建使用者身體份資訊
        ActiveUser activeUser = new ActiveUser();
        activeUser.setUserid(username);
        activeUser.setUsername(username);
        activeUser.setUsercode(username);
        activeUser.setMenus(menus);

        // 返回認證資訊由父類AuthenticatingRealm進行認證
        SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(
                activeUser, password, getName());

        return simpleAuthenticationInfo;
    }

    // 授權
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(
            PrincipalCollection principals) {
        // 獲取身份資訊
        ActiveUser activeUser = (ActiveUser) principals.getPrimaryPrincipal();
        //使用者id
        String userid = activeUser.getUserid();
        // 根據使用者id從資料庫中查詢許可權資料
        // ....這裡使用靜態資料模擬
        List<String> permissions = new ArrayList<String>();
        permissions.add("item:query");
        permissions.add("item:update");

        // 將許可權資訊封閉為AuthorizationInfo

        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        for (String permission : permissions) {
            simpleAuthorizationInfo.addStringPermission(permission);
        }

        return simpleAuthorizationInfo;
    }

}

5、登入controller :

//使用者登陸頁面
    @RequestMapping("/login")
    public String login()throws Exception{
        return "login";
    }
    // 使用者登陸提交
    @RequestMapping("/loginsubmit")
    public String loginsubmit(Model model, HttpServletRequest request)
            throws Exception {

        // shiro在認證過程中出現錯誤後將異常類路徑通過request返回
        String exceptionClassName = (String) request
                .getAttribute("shiroLoginFailure");
        if (UnknownAccountException.class.getName().equals(exceptionClassName)) {
            throw new CustomException("賬號不存在");
        } else if (IncorrectCredentialsException.class.getName().equals(
                exceptionClassName)) {
            throw new CustomException("使用者名稱/密碼錯誤");
        } else{
            throw new Exception();//最終在異常處理器生成未知錯誤
        }
    }

6、退出

由於使用shiro的sessionManager,不用開發退出功能,使用shiro的logout攔截器即可

<!-- 退出攔截,請求logout.action執行退出操作 -->
/logout.action = logout

注意:如需新增MD5校驗需要修改applicationContext-shiro.xml:

<!-- 憑證匹配器 -->
    <bean id="credentialsMatcher"
        class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
        <property name="hashAlgorithmName" value="md5" />
        <property name="hashIterations" value="1" />
    </bean>

<!-- 自定義 realm -->
    <bean id="userRealm" class="cn.itcast.ssm.realm.CustomRealm1">
        <property name="credentialsMatcher" ref="credentialsMatcher" />
    </bean>

shiro快取 配置:

在applicationContext-shiro.xml中配置快取管理器:

<!-- 安全管理器 -->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <property name="realm" ref="userRealm" />
        <property name="sessionManager" ref="sessionManager" />
        <property name="cacheManager" ref="cacheManager"/>
    </bean>

<!-- 快取管理器 -->
    <bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
    </bean>

session管理 :

在applicationContext-shiro.xml中配置sessionManager

<!-- 安全管理器 -->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <property name="realm" ref="userRealm" />
        <property name="sessionManager" ref="sessionManager" />
    </bean>
<!-- 會話管理器 -->
    <bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
        <!-- session的失效時長,單位毫秒 -->
        <property name="globalSessionTimeout" value="600000"/>
        <!-- 刪除失效的session -->
        <property name="deleteInvalidSessions" value="true"/>
    </bean>

配置記住我【下次免登陸】

1、使用者身份實現java.io.Serializable介面【即使用者實體類】

2、修改applicationContext-shiro.xml中對FormAuthenticationFilter的配置:

       <bean id="formAuthenticationFilter" class="org.apache.shiro.web.filter.authc.FormAuthenticationFilter"> 改為  如下:

<bean id="formAuthenticationFilter"

class="cn.itcast.ssm.shiro.MyFormAuthenticationFilter">

<!-- 表單中賬號的input名稱 -->

<property name="usernameParam" value="usercode" />

<!-- 表單中密碼的input名稱 -->

<property name="passwordParam" value="password" />

<property name="rememberMeParam" value="rememberMe"/>

<!-- loginurl:使用者登陸地址,此地址是可以http訪問的url地址 -->

<property name="loginUrl" value="/loginsubmit.action" />

</bean>

3、修改applicationContext-shiro.xml

<!-- 安全管理器 -->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <property name="realm" ref="userRealm" />
        <property name="sessionManager" ref="sessionManager" />
        <property name="cacheManager" ref="cacheManager"/>
        <!-- 記住我 -->
        <property name="rememberMeManager" ref="rememberMeManager"/>
    </bean>

<!-- rememberMeManager管理器 -->
    <bean id="rememberMeManager" class="org.apache.shiro.web.mgt.CookieRememberMeManager">
        <property name="cookie" ref="rememberMeCookie" />
    </bean>
    <!-- 記住我cookie -->
    <bean id="rememberMeCookie" class="org.apache.shiro.web.servlet.SimpleCookie">
        <constructor-arg value="rememberMe" />
        <!-- 記住我cookie生效時間30天 -->
        <property name="maxAge" value="2592000" />
    </bean>

登入頁面 新增如下:

<input type="checkbox" name="rememberMe" />自動登陸

附 :

shiro過慮器
過濾器簡稱    對應的java類
anon    org.apache.shiro.web.filter.authc.AnonymousFilter
authc    org.apache.shiro.web.filter.authc.FormAuthenticationFilter
authcBasic    org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter
perms    org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter
port    org.apache.shiro.web.filter.authz.PortFilter
rest    org.apache.shiro.web.filter.authz.HttpMethodPermissionFilter
roles    org.apache.shiro.web.filter.authz.RolesAuthorizationFilter
ssl    org.apache.shiro.web.filter.authz.SslFilter
user    org.apache.shiro.web.filter.authc.UserFilter
logout    org.apache.shiro.web.filter.authc.LogoutFilter


anon:例子/admins/**=anon 沒有引數,表示可以匿名使用。
authc:例如/admins/user/**=authc表示需要認證(登入)才能使用,沒有引數
roles:例子/admins/user/**=roles[admin],引數可以寫多個,多個時必須加上引號,並且引數之間用逗號分割,當有多個引數時,例如admins/user/**=roles["admin,guest"],每個引數通過才算通過,相當於hasAllRoles()方法。
perms:例子/admins/user/**=perms[user:add:*],引數可以寫多個,多個時必須加上引號,並且引數之間用逗號分割,例如/admins/user/**=perms["user:add:*,user:modify:*"],當有多個引數時必須每個引數都通過才通過,想當於isPermitedAll()方法。
rest:例子/admins/user/**=rest[user],根據請求的方法,相當於/admins/user/**=perms[user:method] ,其中method為post,get,delete等。
port:例子/admins/user/**=port[8081],當請求的url的埠不是8081是跳轉到schemal://serverName:8081?queryString,其中schmal是協議http或https等,serverName是你訪問的host,8081是url配置裡port的埠,queryString
是你訪問的url裡的?後面的引數。
authcBasic:例如/admins/user/**=authcBasic沒有引數表示httpBasic認證

ssl:例子/admins/user/**=ssl沒有引數,表示安全的url請求,協議為https
user:例如/admins/user/**=user沒有引數表示必須存在使用者,當登入操作時不做檢查
注:
anon,authcBasic,auchc,user是認證過濾器,
perms,roles,ssl,rest,port是授權過濾器

shiro的jsp標籤

Jsp頁面新增:
<%@ tagliburi="http://shiro.apache.org/tags" prefix="shiro" %>

標籤名稱    標籤條件(均是顯示標籤內容)
<shiro:authenticated>    登入之後
<shiro:notAuthenticated>    不在登入狀態時
<shiro:guest>    使用者在沒有RememberMe時
<shiro:user>    使用者在RememberMe時
<shiro:hasAnyRoles name="abc,123" >    在有abc或者123角色時
<shiro:hasRole name="abc">    擁有角色abc
<shiro:lacksRole name="abc">    沒有角色abc
<shiro:hasPermission name="abc">    擁有許可權資源abc
<shiro:lacksPermission name="abc">    沒有abc許可權資源
<shiro:principal>    顯示使用者身份名稱
 <shiro:principal property="username"/>     顯示使用者身份中的屬性值

注: 該文章屬於轉載,如有侵權,還請留言告知,將進行刪除。