Shiro後臺實現驗證權限

  今天發現一個問題:使用shiro的時候,雖然隱藏掉了一些菜單,可是當咱們經過get請求直接訪問菜單的時候仍是會訪問到,也就是shiro能夠在界面實現隱藏一些信息,可是沒有真正的根據權限碼驗證請求,因而本身在後臺實現驗證。html

  

需求:有權限(權限碼是systemmanager:settings)的人能夠點擊系統設置跳轉到系統設置頁面,沒權限的人看不到菜單,可是經過get訪問能夠訪問到,因而須要在後臺攔截。java

實現思路:在須要精確驗證的方法開始先驗證權限,若是驗證成功啥也不作,驗證失敗的話就拋出一個沒有權限的異常。在攔截器中捕捉到異常就記錄日誌,並返回到提醒頁面。spring

 

1.  驗證Shiro權限的工具類(此工具還能夠進一步完善,封裝爲判斷是否有指定角色,或者有任意角色)

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測試

 

 

 2.自定義異常(若是不自定義異常,也能夠在程序中拋出一個運行時異常throw new RuntimeException("XXXXX");)

   必須繼承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);
    }
}

 

 3.測試Action

   方法開始先驗證權限,可是沒有捕捉異常,若是驗證失敗異常會拋出在攔截器中被捕捉。

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";
    }

}

 

 4.struts全局異常攔截器

  捕捉到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;
    }

}

 

 5.Struts.xml配置全局異常錯誤界面:

  返回值是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>

 

6.noPermissionError.jsp頁面

  給出沒權限提醒。

<%@ 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>

 

7.測試:

 

 

至此,完成了後臺驗證,也就是在全部方法開始先驗證權限。

 

 

還有另外一種辦法就是自定義註解實現權限驗證,有點相似於shiro自帶的註解驗證權限,參考:http://www.javashuo.com/article/p-opjkeauo-w.html

相關文章
相關標籤/搜索