今天發現一個問題:使用shiro的時候,雖然隱藏掉了一些菜單,可是當咱們經過get請求直接訪問菜單的時候仍是會訪問到,也就是shiro能夠在界面實現隱藏一些信息,可是沒有真正的根據權限碼驗證請求,因而本身在後臺實現驗證。html
需求:有權限(權限碼是systemmanager:settings)的人能夠點擊系統設置跳轉到系統設置頁面,沒權限的人看不到菜單,可是經過get訪問能夠訪問到,因而須要在後臺攔截。java
實現思路:在須要精確驗證的方法開始先驗證權限,若是驗證成功啥也不作,驗證失敗的話就拋出一個沒有權限的異常。在攔截器中捕捉到異常就記錄日誌,並返回到提醒頁面。spring
package cn.xm.exam.utils; import org.apache.shiro.SecurityUtils; import org.apache.shiro.subject.Subject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import cn.xm.exam.bean.system.User; import cn.xm.exam.exception.NoPermissionException; /** * 驗證shiro權限的工具類 * * @author QiaoLiQiang * @time 2018年11月3日下午9:30:46 */ public class ShiroPermissionUtils { private static final Logger log = LoggerFactory.getLogger(ShiroPermissionUtils.class); private ShiroPermissionUtils() { } /** * 檢查當前用戶是否有權限(任意一項) * * @param permissionCodes * 任意權限 * @throws NoPermissionException */ public static void checkPerissionAny(String... permissionCodes) { if (permissionCodes == null || permissionCodes.length == 0) { return; } // 獲取用戶信息 Subject currentUser = SecurityUtils.getSubject(); for (String permission : permissionCodes) { boolean permitted = currentUser.isPermitted(permission);// 判斷是否有權限 if (permitted) { return; } } // 沒權限就拋出一個異常 Object principal = currentUser.getPrincipal(); if (principal instanceof User) { User user = (User) principal; log.error("user {} no permission !", user.getUsername()); } throw new NoPermissionException("no permission "); } /** * 檢查當前用戶是否有權限(全部的) * * @param permissionCodes * 任意權限 * @throws NoPermissionException */ public static void checkPerissionAll(String... permissionCodes) { if (permissionCodes == null || permissionCodes.length == 0) { return; } // 獲取用戶信息 Subject currentUser = SecurityUtils.getSubject(); for (String permission : permissionCodes) { boolean permitted = currentUser.isPermitted(permission);// 判斷是否有權限 if (!permitted) { // 沒權限就拋出一個異常 Object principal = currentUser.getPrincipal(); if (principal instanceof User) { User user = (User) principal; log.error("user {} no permission !", user.getUsername()); } throw new NoPermissionException("no permission "); } } } }
解釋:apache
(1)Subject currentUser = SecurityUtils.getSubject(); 先獲取到Subject,json
(2)boolean permitted = currentUser.isPermitted(permission); 而後驗證權限jsp
(3)若是驗證失敗就記錄日誌,(獲取到subject中的principal,principal實際上是認證的時候裝進SimpleAuthenticationInfo的user對象)ide
Object principal = currentUser.getPrincipal();
if (principal instanceof User) {
User user = (User) principal;
log.error("user {} no permission !", user.getUsername());
}
throw new NoPermissionException("no permission ");工具
認證時候裝進去的User對象:---principal測試
必須繼承RuntimeException,運行時異常不須要在拋出異常的時候顯示的捕捉或者聲明(throws.....),若是繼承Exception爲檢查異常,須要捕捉或者throws聲明.spa
package cn.xm.exam.exception; /** * 沒有權限異常 * * @author QiaoLiQiang * @time 2018年11月3日下午9:34:12 */ public class NoPermissionException extends RuntimeException { /** * */ private static final long serialVersionUID = -4442982597754920924L; public NoPermissionException(String msg) { super(msg); } }
方法開始先驗證權限,可是沒有捕捉異常,若是驗證失敗異常會拋出在攔截器中被捕捉。
package cn.xm.exam.action.system; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Controller; import com.opensymphony.xwork2.ActionSupport; import cn.xm.exam.utils.ShiroPermissionUtils; @Controller @Scope("prototype") public class SettingsAction extends ActionSupport { /** * serial */ private static final long serialVersionUID = -5885555441378384728L; private static final Logger log = LoggerFactory.getLogger(ShiroPermissionUtils.class); public String settings() { ShiroPermissionUtils.checkPerissionAny("systemmanager:settings"); return "settings"; } }
捕捉到NoPermissionException異常就返回noPermissionError在全局結果集中處理
package cn.xm.exam.interceptor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.opensymphony.xwork2.ActionInvocation; import com.opensymphony.xwork2.interceptor.Interceptor; import cn.xm.exam.exception.NoPermissionException; public class ExceptionInterception implements Interceptor { private static final Logger log = LoggerFactory.getLogger(ExceptionInterception.class); /** * */ private static final long serialVersionUID = 2268867259828199826L; @Override public void destroy() { } @Override public void init() { } @Override public String intercept(ActionInvocation arg0) throws Exception { log.info("enter ExceptionInterception intercept ... "); String result = ""; try { result = arg0.invoke(); log.info("result -> {}", result); } catch (NoPermissionException e) { log.error("no permission", e); return "noPermissionError"; } catch (Throwable e) { log.error("未處理的異常在攔截器被攔截,class:{}", arg0.getAction().getClass(), e); return "interceptorError"; } log.debug("exit ExceptionInterception intercept ... "); return result; } }
返回值是noPermissionError跳轉到noPermissionError.jsp頁面
<package name="interceptPackage" extends="json-default"> <!-- 攔截器 --> <interceptors> <!-- 定義剛纔的攔截器 --> <interceptor name="exceptionInterceptor" class="cn.xm.exam.interceptor.ExceptionInterception"></interceptor> <!-- 定義攔截器棧 --> <interceptor-stack name="myStack"> <!-- 攔截器棧裏面能夠引用另一個攔截器,也能夠引用另一個攔截器棧 --> <interceptor-ref name="defaultStack"></interceptor-ref> <interceptor-ref name="exceptionInterceptor"></interceptor-ref> </interceptor-stack> </interceptors> <!-- 這句是設置全部Action自動調用的攔截器堆棧 --> <default-interceptor-ref name="myStack" /> <!-- 攔截器攔截的全局異常 --> <global-results> <result name="interceptorError">/interceptorError.jsp</result> <result name="noPermissionError">/noPermissionError.jsp</result> </global-results> </package>
給出沒權限提醒。
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <% String path = request.getContextPath(); String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/"; %> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>錯誤提醒</title> </head> <body> <br /> <span style="font-weight: bold; font-size: 20px; margin: 20px;">對不起,您沒有權限訪問該請求!</span> <br /> </body> </html>
至此,完成了後臺驗證,也就是在全部方法開始先驗證權限。
還有另外一種辦法就是自定義註解實現權限驗證,有點相似於shiro自帶的註解驗證權限,參考:http://www.javashuo.com/article/p-opjkeauo-w.html