Shiro基礎使用——加密、session管理、Spring整合和註解開發

繼續《Shiro基礎應用——角色和權限校驗》中的案例

一、整合到Spring

1.1 導入依賴

<!-- 其他依賴和web集成中 一致 ,此處省略-->
<!-- 新增一個依賴 用於在工廠中生產 ShiroFilter-->
<!-- 會傳遞導入shiro-core 和 shiro-web ,所以這兩個依賴可以不用再導入-->
<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-spring</artifactId>
    <version>1.4.0</version>
</dependency>

1.2 配置bean.xml文件

這裏可以單獨設置一個【shiro_bean.xml】文件,然後在【bean.xml】文件中加入如下字段,可以是兩個xml文件關聯到一起

<!--關聯另一個bean.xml-->
<import resource="classpath:shiro_bean.xml"/>

配置文件的邏輯

在這裏插入圖片描述

相關的配置

<!--shiro配置-->
    <bean id="myRealm" class="com.rj.realm.MyRealm">
        <!--Realm,這樣在myRealm類中就可以不需要啓動三個ContextLoader了-->
        <property name="userService" ref="userService"/>
        <property name="roleService" ref="roleService"/>
        <property name="permissionService" ref="permissionService"/>

        <!--身份驗證匹配,主要是導入加密模式等數據-->
        <property name="credentialsMatcher">
            <bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
                <property name="hashAlgorithmName" value="md5"/>
                <!-- true means hex encoded, false means base64 encoded -->
                <property name="storedCredentialsHexEncoded" value="false"/>
                <property name="hashIterations" value="10000"/>
            </bean>
        </property>
    </bean>

<!--自定義記住我的cookie的屬性-->
    <bean id="remembermecookie" class="org.apache.shiro.web.servlet.SimpleCookie">
        <property name="name" value="rememberMe"/>
        <property name="httpOnly" value="true"/>
        <!-- cookie的生命週期,單位:秒 -->
        <property name="maxAge" value="120"/>
    </bean>
    <!--將自定義好的cookie注入CookieRememberMeManager管理類,然後就可以將其注入到SecurityManager中-->
    <bean id="rememberMeManager" class="org.apache.shiro.web.mgt.CookieRememberMeManager">
        <property name="cookie" ref="remembermecookie"/>
    </bean>

    <!--自定義session會話管理,同樣由SimpleCookie創建-->
    <bean id="sessionId" class="org.apache.shiro.web.servlet.SimpleCookie">
        <property name="name" value="sessionId"/>
        <property name="httpOnly" value="true"/>
        <!-- cookie過期時間,-1:存活一個會話 ,單位:秒,表示cookie結束的時候,會話也結束-->
        <property name="maxAge" value="-1"/>
    </bean>
    <bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
        <!-- 默認值和配置中給出的一致,所bean:sessionIdCookie 可以省略 -->
        <property name="sessionIdCookie" ref="sessionId"/>
        <!-- session全局超時時間, 單位:毫秒 ,默認值爲1800000,30分鐘-->
        <property name="globalSessionTimeout" value="120000"/>

        <!--將監聽器給到sessionManager中-->
        <property name="sessionListeners">
            <list>
                <bean class="com.rj.listener.MySessionListener"/>
            </list>
        </property>

        <!--開啓檢測器,默認開啓,單位毫秒,默認1小時-->
        <property name="sessionValidationSchedulerEnabled" value="true"/>
        <property name="sessionValidationInterval" value="40000"/>
    </bean>

    <!-- 聲明SecurityManager核心組件,將自定義的realm注入到SecurityManager -->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <property name="realm" ref="myRealm"/>
        <property name="rememberMeManager" ref="rememberMeManager"/>
        <property name="sessionManager" ref="sessionManager"/>
    </bean>

    <!-- 生產SpringShiroFilter,注入SecurityManager核心組件
     ( 持有shiro的過濾相關規則,可進行請求的過濾校驗,校驗請求是否合法 )
    -->
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <property name="securityManager" ref="securityManager"/>
        <property name="loginUrl" value="/user/login"/>
        <property name="unauthorizedUrl" value="/user/error"/>
        <!--<property name="" value="/"/>-->
        <property name="filterChainDefinitions">
            <value>
                /user/login = anon
                /user/all = authc,roles["管理員"]
            </value>
        </property>
    </bean>

可以發現,與ini配置文件基本一致,需要將【myRealm】、【加密】、【cookie】、【session】等都設置好,然後最終都要注入到【securityManager】中

1.3 配置web.xml文件

之前的【ShiroFileter】和【EnvironmentLoaderListener】可以刪除

<!-- 會從spring工廠中獲取和它同名的bean,(id="shiroFilter")
     接到請求後調用bean的doFilter方法,進行訪問控制。
    -->
    <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>
    <!-- EnvironmentLoaderListener不再需要,因爲shiro環境已由spring初始化
         springMVC,spring配置不變 -->


二 、加密

用戶的密碼是不允許明文存儲的,因爲一旦數據泄露,用戶的隱私信息會完全暴露。

密碼必須結果加密,生成密文,然後數據庫中只存儲用戶的密碼的密文。

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-g5qlofpI-1570709713350)(mdpic/jiami.jpg)]

在加密過程中需要使用到一些**“不可逆加密”**,如 md5,sha

所謂不可逆是指:

  • 加密函數A, 明文 “abc”, A(“abc”) = “密文”,不能通過 “密文” 反推出 “abc”,即使密文泄露密碼仍然安全。

2.1 加密介紹

shiro支持hash(散列)加密,常見的如 md5, sha等

  • 基本加密過程

    md5(明文),sha(明文) 得到明文的密文,但明文可能比較簡單導致密文容易被破解。
    
  • 加鹽加密過程

    系統生成一個隨機salt=“xxxxxx”, md5(明文+salt) ,sha(明文+salt),則提升了密文的複雜度。

  • 加鹽多次迭代加密過程

    如果迭代次數爲2,則加密2次: md5(明文+salt)=密文a , md5(密文a+salt)=最終密文

    ​ sha(明文+salt)=密文a , sha(密文a+salt)=最終密文

    ​ 則進一步提升了密文的複雜度,和被破解的難度。

加密過程中建議使用salt,並指定迭代次數,迭代次數的建議值1000+

實例代碼:

String password="abc";//密碼明文
String salt=UUID.randomUUID().toString();//鹽
Integer iter = 1000;//迭代次數
String pwd = new Md5Hash(password, salt,iter).toString(); //md5加密
String pwd = new Md5Hash(password, salt, iter).toBase64(); //加密後轉base64

String pwd = new Sha256Hash(password, salt, iter).toString();//sha256加密
String pwd = new Sha256Hash(password, salt, iter).toBase64();//加密後轉base64

String pwd = new Sha512Hash(password, salt, iter).toString();//sha256加密
String pwd = new Sha512Hash(password, salt, iter).toBase64()//加密後轉base64

1.2 加密

增加用戶,或修改用戶密碼時,涉及到密碼的加密

在註冊用戶的業務中,對用戶提交的密碼加密即可。

注意:之前的用戶表,並未考慮存儲加密相關信息,所以此時需要對用戶表做出改進,

加一列【 salt varchar(50) 】,用於存儲每個用戶的鹽。

在這裏插入圖片描述

爲了能夠方便處理【迭代次數】,我們單獨設計工具類。

public class MyConstant {
    public static final Integer CONSTANT=10000;
}

service業務層處理加密

@Override
public void add(User user) {
    //加密處理
    String salt = UUID.randomUUID().toString();
    String s = new Md5Hash(user.getPassword(),salt, MyConstant.CONSTANT).toBase64();
    user.setPassword(s);
    //這裏需要將鹽加入到數據庫,因爲鹽是隨機生成的,要保證登錄沒有問題
    user.setSalt(salt);
    userDao.add(user);
}

2.3 密碼比對

登錄認證身份時,涉及到密碼 比對 過程

注意,加密過程中使用的加密屬性,和此處使用的加密屬性 必須一致:

sha256,迭代1000次,使用base64格式化密文

2.3.1 指定比對器

<!--身份驗證匹配,主要是導入加密模式等數據-->
        <property name="credentialsMatcher">
            <bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
                <property name="hashAlgorithmName" value="md5"/>
                <!-- <property name="hashAlgorithmName" value="sha-256"/> -->
                <!--true標示hex算法,false是base64算法-->
                <property name="storedCredentialsHexEncoded" value="false"/>
                <property name="hashIterations" value="10000"/>
            </bean>
        </property>

2.3.2 修改Realm

doGetAuthenticationInfo方法的返回值需要做修改

<bean id="myRealm" class="com.rj.realm.MyRealm">
        <!--Realm,這樣在myRealm類中就可以不需要啓動三個ContextLoader了-->
        <property name="userService" ref="userService"/>
        <property name="roleService" ref="roleService"/>
        <property name="permissionService" ref="permissionService"/>
/**
* 既然使用了spring工廠,則可以註解使用業務層成員變量,但是這裏建議使用lombok的@setter
* 也就是不建議使用註解注入,而是在【shiro_bean.xml】文件中注入
* 【注意】必須有【set】方法
*/
@Setter
public class MyRealm extends AuthorizingRealm {
    private UserService userService;
    private RoleService roleService;
    private PermissionService permissionService;
   
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        System.out.println("在realm中 查詢權限");
        //獲取用戶名
        String username = (String) principals.getPrimaryPrincipal();
        Set<String> roles = roleService.getRolenameByUsername(username);
        Set<String> perms = permissionService.getPernameByUsername(username);
        //將查詢的信息封裝,然後返回結果
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        simpleAuthorizationInfo.setRoles(roles);
        simpleAuthorizationInfo.setStringPermissions(perms);
        return simpleAuthorizationInfo;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        System.out.println("在Realm中查詢身份");

        // 獲取用戶登錄時發送來的用戶名
        String username = (String) token.getPrincipal();

        //在數據庫中查詢信息
        User user = userService.findByUsername(username);

        //判斷是否存在,如果不存在返回null,該類會在後續直接拋出異常UnknownAccountException
        if (user == null) {
            return null;
        }
        
        //需要加鹽對密碼進行處理
        //對鹽進行格式轉化
        ByteSource saltBytes = ByteSource.Util.bytes(user.getSalt());
        return new SimpleAuthenticationInfo(user.getUsername(),user.getPassword(),saltBytes,this.getName());
    }
}

這裏要注意一下,這個【saltBytes】並不是給【user.getPassword】的,因爲從數據庫獲取的密碼已經是加密的了,這裏是給到【shiro_bean.xml】的【credentialsMatcher】屬性進行處理,會給到從前端獲取的【token】的【password】,這樣才能進行比對驗證。



三、記住我RememberMe

在登錄後,可以將用戶名存在cookie中,下次訪問時,可以先不登錄,就可以識別身份。

在確實需要身份認證時,比如購買,支付或其他一些重要操作時,再要求用戶登錄即可,用戶體驗好。

由於可以保持用戶信息,系統後臺也可以更好的監控、記錄用戶行爲,積累數據。

3.1 代碼

”記住我“ 起點在登錄時刻:Subject.login(UsernameAndPasswordToken)

而是否確定要“記住我”,由登錄時的token控制開關:token.setRememberMe(true);

Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
//如果需要記住我的話,需要在token中設置
token.setRememberMe(true);//shiro默認支持”記住我“,只要有此設置則自動運作。
subject.login(token);

3.2 效果

登錄後效果

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-QfEbz6SW-1570709713352)(mdpic/rememberme.jpg)]

3.3 頁面中顯示

在頁面中顯示,cookie中記錄的用戶信息

<shiro:user> 當有記住我信息,或已登錄,則顯示標籤體內容

<shiro:principal> 獲取用戶信息

注意:首頁的訪問路徑的過濾器 不能是 authc,只能是 user 或 anon

<!-- 首頁 xx.jsp -->
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>
<html>
    <body>
        <h2>Hello World! </h2>
        <!-- 重點在此:通過如下shiro標籤顯示 -->
        <shiro:user>
            歡迎您,<shiro:principal/>  <a href="#">退出登錄</a>
        </shiro:user>
    </body>
</html>

登錄的時候,自動填充用戶名

<!-- 登錄頁面 login.jsp 自動填充用戶名 -->
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>
<html>
    <head>
        <title>Title</title>
    </head>
    <body>
        <form action="<c:url value="/user/login"/>" method="post">
            <!-- 重點在此:<shiro:principal/> -->
            username:<input type="text" name="username" value="<shiro:principal/>"> <br>
            password:<input type="password" name="password"><br>
            <input type="submit" value="登錄">
        </form>
    </body>
</html>

3.4 自定義記住我的cookie的時間和名稱

如果需要做自定義,可以明確定義如下兩個組件:

SimpleCookie:封裝cookie的相關屬性,定製cookie寫出邏輯(詳見:addCookieHeader())

CookieRememberMeManager:接受SecurityManager調度,獲取用戶信息,加密數據,並調度SimpleCookie寫出cookie。

<!-- 之前的配置不變,添加如下配置 -->
<!-- remember me -->
<bean id="rememberMeCookie" class="org.apache.shiro.web.servlet.SimpleCookie">
    <property name="name" value="rememberMe"/>
    <property name="httpOnly" value="true"/>
    <!-- cookie的生命週期,單位:秒 -->
    <property name="maxAge" value="2592000"/><!-- 30天 -->
</bean>

<!--如果要注入到securityManager中,必須先注入到rememberMeManager中-->
<bean id="rememberMeManager" class="org.apache.shiro.web.mgt.CookieRememberMeManager">
    <!-- 注入SimpleCookie -->
    <property name="cookie" ref="rememberMeCookie"/>
</bean>

<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
	...
    <!-- CookieRememberMeManager注入給SecurityManager,
         SecurityManager在處理login時,如果login成功,則會通過rememberMeManager做"記住我",
         將用戶名存入cookie
	-->
    <property name="rememberMeManager" ref="rememberMeManager"/>
</bean>


四、Session管理

shiro作爲一款安全管理框架,對狀態保持有很強的需要。

比如最常用的用戶認證,就必需狀態的保持,以及其他的一些功能實現的需要。

【shiro需要:認證中的 記住我中的用戶名 正式登陸的用戶名】【 開發者需要:其他功能中需要存入session的值 】

shiro提供了一整套session管理方案.

1. shiro的session方案和任何容器無關(如servlet容器);

2. javaSE也可以使用;相關組件都是pojo對ioc極其友好(方便的管理對象和滿足依賴關係,定製參數)

3. 可以方便的擴展定製存儲位置(內存,緩存,數據庫等)

4. 對web透明支持:用了shiro的session後,項目中關於session的代碼完全不用任何改動

5. 提供了全面的session監聽機制,和session檢測機制,對session可以細粒度操作

即,使用了shiro後,採用shiro的session方案是最優的方案。

4.1 javaSE環境 (瞭解)

shiro 的session管理方案,可以在javaSE中使用,實用價值不大。

Subject subject = SecurityUtils.getSubject();
//獲取session
Session session = subject.getSession();
//session超時時間,單位:毫秒;0,馬上過期;正數,則空閒對應毫秒後過期;負數,則不會過期
session.setTimeout(10000); 
//session存、取值
session.setAttribute("name","zhj");
session.getAttribute("name");
//獲取sessionID
getSession().getId();
//銷燬session
session.stop();

原理,核心對象:

1. SimpleSession

​ Session的實現類,完成session基本功能。

2. SimpleSessionFactory

​ 生產SimpleSession

3. SessionDAO

​ 默認的實現類:MemorySessionDAO,由SessionManager創建,

負責存儲所有session對象,存儲位置:內存

4. DefaultSessionManager

​ 由SecurityManager創建,負責創建、管理SessionFactory和SessionDAO。

//核心類演示: ( ops:實際開發不用手動創建,shiro會初始化 )
//通過SecurityManager 獲得 SessionManager
DefaultSessionManager sessionManager = (DefaultSessionManager)securityManager.getSessionManager();
//通過SessionManager獲得SessionFactory
SimpleSessionFactory sessionFactory = (SimpleSessionFactory) sessionManager.getSessionFactory();
//通過SessionManager獲得SessionDAO
MemorySessionDAO sessionDAO = (MemorySessionDAO)sessionManager.getSessionDAO();
//通過SessionFactory獲得Session
SimpleSession session1 = (SimpleSession) sessionFactory.createSession(null);
//通過Session做具體操作
session1.setAttribute("name","zhangsan");
System.out.println(session1.getAttribute("name"));

4.2 javaEE環境

<!-- 增加session管理相關配置 -->
<!-- 會話Cookie模板 默認可省-->
<bean id="sessionIdCookie" class="org.apache.shiro.web.servlet.SimpleCookie">
    <!-- cookie的 key="sid" -->
    <property name="name" value="JSESSIONID"/>
    <!-- 只允許http請求訪問cookie -->
    <property name="httpOnly" value="true"/>
    <!-- cookie過期時間,-1:存活一個會話 ,單位:秒 ,默認爲-1-->
    <property name="maxAge" value="-1"/>
</bean>
<!--同rememberMe一樣,需要先注入到sessionManager中,然後才能注入到securityManager中-->
<bean id="sessionManager" 
      class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
    <!-- 默認值和配置中給出的一致,所bean:sessionIdCookie 可以省略 -->
    <property name="sessionIdCookie" ref="sessionIdCookie"/>
    <!-- session全局超時時間, 單位:毫秒 ,30分鐘 默認值爲1800000-->
    <property name="globalSessionTimeout" value="1800000"/>
</bean>

<!-- 將sessionManager關聯到SecurityManager -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
    ...
    <!-- 增加配置sessionManager -->
    <property name="sessionManager" ref="sessionManager"/>
</bean>

4.3 Session監聽

session有三個核心過程:創建、過期、停止

​ **過期:**session的默認過期時間爲30分鐘。通過比對最近一次使用時間和當前使用時間判斷

​ session不會自動報告過期,需檢測器檢測時,或再次訪問時,纔可以識別是否過期並移除。

​ **停止:**用戶主動logout;主動調用session.stop(); 兩種情況會將session標誌爲停止狀態。

// 定義監聽類 exentends SessionListenerAdapter
//IDEA快捷鍵【ctrl+O】可以選擇繼承方法
public class MySessionListener extends SessionListenerAdapter{
    //當有session創建時 觸發
    @Override
    public void onStart(Session session) {
        System.out.println("session:"+session.getId()+" start");
    }
    //當有session停止時 觸發
    @Override
    public void onStop(Session session) {
        System.out.println("session:"+session.getId()+" stop");
    }
    //當有session過期時 觸發
    // 但不會主動觸發,需要再次訪問時,即又要使用session時纔會發現session過期,並觸發。
    @Override
    public void onExpiration(Session session) {
        System.out.println("session:"+session.getId()+" expired");
    }
}

配置監聽類,關聯給SessionManager

<bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
    ...
    <property name="sessionListeners">
        <list>
            <bean class="com.zhj.listener.MySessionListener"></bean>
        </list>
    </property>
    ...
</bean>

4.4 Session檢測

用戶如果沒有主動退出登錄,只是關閉瀏覽器,則session是否過期無法獲知,也就不能停止session。

爲此,shiro提供了session的檢測機制,可以定時發起檢測,識別session過期 並停止session

<!-- sessionManager默認開啓session檢測機制 -->
<bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
    ...
    <!-- 開啓檢測器,默認開啓 -->
    <property name="sessionValidationSchedulerEnabled" value="true"/>
    <!--- 檢測器運行間隔,單位:毫秒  默認1小時
		    //檢測到過期後,會直接將session刪除
		    protected void afterExpired(Session session) {
                if (isDeleteInvalidSessions()) {
                    delete(session);
                }
            }
    -->
    <property name="sessionValidationInterval" value="3600000"/>
    ...
</bean>

如上,通過檢測器,定時的檢測session,並及時移除無效session,釋放資源。



五、註解開發

shiro提供了一系列的訪問控制的註解,可以簡化開發過程。

<!-- 註解加載Controller中,原理是會對Controller做增強,切入訪問控制邏輯,所以需要如下依賴 -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
    <version>4.3.6.RELEASE</version>
</dependency>

5.1 配置mvc.xml

必須在【mvc.xml】中配置,配置以後,僅僅可以將原【shiro_bean.xml】文件中的【ShiroFilter】中的驗證判斷可以省略。

<!-- enable shiro's annotation-->
<bean id="lifecycleBeanPostProcessor" 		
      class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
<!-- 自動代理生成器,等價於aop:config;
     aop:config 或 AutoProxyCreator兩者選其一,spring官方提醒千萬不要同時使用。

<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" 
      depends-on="lifecycleBeanPostProcessor"/>
-->
<aop:config></aop:config>
<!-- 在此bean的構建過程中,初始化了一些額外功能和piontcut
     interceptors.add(new RoleAnnotationMethodInterceptor(resolver));
     interceptors.add(new PermissionAnnotationMethodInterceptor(resolver));
     interceptors.add(new AuthenticatedAnnotationMethodInterceptor(resolver));
     interceptors.add(new UserAnnotationMethodInterceptor(resolver));
     interceptors.add(new GuestAnnotationMethodInterceptor(resolver));
-->
<bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
	<property name="securityManager" ref="securityManager"/>
</bean>

5.2 註解使用

加在類上

@Controller
@RequestMapping("/user")
@RequiresAuthentication //類中的所有方法都需要身份認證
@RequiresRoles(value={"manager","admin"},logical= Logical.OR)//類中的所有方法都需要角色,"或"
public class ShiroController {
	...
}

加在方法上

@Controller
@RequestMapping("/user")
public class ShiroController2{
	...
    @RequiresPermissions({"user:query”,“user:delete"}) //有對應權限,默認是 "且"
    @RequiresUser //記住我 或 已身份認證
    public String hello(){
		...
    }
    @RequiresGuest //遊客身份
    public String hello2(){
		...
    }
}

配置修改

<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
    <property name="securityManager" ref="securityManager"/>
    <!-- 不再需要,此時如果身份或權限不通過,會拋出異常,需要異常解析器處理
    <property name="loginUrl" value="/user/login/page"/>
    <property name="unauthorizedUrl" value="/error.jsp"/>
    <property name="filterChainDefinitions">
        <value>
            /user/query=anon  如下不再需要,登出可以保留,也可以自己寫handler中subject.logout()
            /user/insert=authc,roles["banfu"]
            /user/update=authc,perms[""student:update""]
            /order/insert=authc,roles["xuewei"]
            /user/logout=logout
        </value>
    </property>-->
</bean>

5.3 異常處理

<!-- mvc.xml中:MVC的自定義異常處理器,用於處理權限或身份認證不通過時的異常處理-->
<bean class="com.zhj.ex.handler.MyExHandler"></bean>
public class MyExceptionResolver implements HandlerExceptionResolver{
    @Override
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        System.out.println(ex.getClass());
        ex.printStackTrace();//開發時必需
        ModelAndView mv = new ModelAndView();
        if(ex instanceof IncorrectCredentialsException || ex instanceof UnknownAccountException){
            //跳轉登錄頁面,重新登錄
            mv.setViewName("redirect:/user/login");
        }else if(ex instanceof UnauthorizedException){// 角色不足  權限不足
            //跳轉權限不足的頁面
            mv.setViewName("redirect:/user/perms/error");
        }else if(ex instanceof UnauthenticatedException){//沒有登錄 沒有合法身份
            //跳轉登錄頁面,重新登錄
            mv.setViewName("redirect:/user/login");
        }
        return mv;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章