zoukankan      html  css  js  c++  java
  • Shiro后台实现验证权限

      今天发现一个问题:使用shiro的时候,虽然隐藏掉了一些菜单,但是当我们通过get请求直接访问菜单的时候还是会访问到,也就是shiro可以在界面实现隐藏一些信息,但是没有真正的根据权限码验证请求,于是自己在后台实现验证。

      

    需求:有权限(权限码是systemmanager:settings)的人可以点击系统设置跳转到系统设置页面,没权限的人看不到菜单,但是通过get访问可以访问到,于是需要在后台拦截。

    实现思路:在需要精确验证的方法开始先验证权限,如果验证成功啥也不做,验证失败的话就抛出一个没有权限的异常。在拦截器中捕捉到异常就记录日志,并返回到提醒页面。

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

    解释:

      (1)Subject currentUser = SecurityUtils.getSubject();    先获取到Subject,

      (2)boolean permitted = currentUser.isPermitted(permission);     然后验证权限

      (3)如果验证失败就记录日志,(获取到subject中的principal,principal其实是认证的时候装进SimpleAuthenticationInfo的user对象)

    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声明.

    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自带的注解验证权限,参考:https://www.cnblogs.com/qlqwjy/p/7257616.html

  • 相关阅读:
    [JAVA] 运行 java HelloWorld 命令,提示“错误: 找不到或无法加载主类
    「Ubuntu」 终端更新时,报错
    【MATLAB】 运行Simulink时出现报错
    Ubuntu提示boot内存不足
    python+unittest+requests实现接口自动化的方法
    Python + Requests + Unittest接口自动化测试实例分析
    七.测试执行的log读取
    五.DDT测试驱动
    操作json文件
    四.爬取拉勾网实例
  • 原文地址:https://www.cnblogs.com/qlqwjy/p/9902711.html
Copyright © 2011-2022 走看看