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.自定义异常

  必须继承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

原文地址:https://www.cnblogs.com/qlqwjy/p/9902711.html

时间: 2024-10-10 02:35:05

Shiro后台实现验证权限的相关文章

SpringMVC+Apache Shiro+JPA(hibernate)案例教学(二)基于SpringMVC+Shiro的用户登录权限验证

序: 在上一篇中,咱们已经对于项目已经做了基本的配置,这一篇文章开始学习Shiro如何对登录进行验证. 教学: 一.Shiro配置的简要说明. 有心人可能注意到了,在上一章的applicationContext.xml配置文件中,包含以下配置. <!-- 項目自定义的Realm --> <bean id="shiroDbRealm" class="org.shiro.demo.service.realm.ShiroDbRealm" ><

项目一:第十二天 1、常见权限控制方式 2、基于shiro提供url拦截方式验证权限 3、在realm中授权 5、总结验证权限方式(四种) 6、用户注销7、基于treegrid实现菜单展示

1 课程计划 1. 常见权限控制方式 2. 基于shiro提供url拦截方式验证权限 3. 在realm中授权 4. 基于shiro提供注解方式验证权限 5. 总结验证权限方式(四种) 6. 用户注销 7. 基于treegrid实现菜单展示 2 常见的权限控制方式 2.1 url拦截实现权限控制 shiro基于过滤器实现的   2.2 注解方式实现权限控制 底层:代理技术     3 基于shiro的url拦截方式验权   <!-- 配置过滤器工厂 --> <bean id="

将 Shiro 作为应用的权限基础 四:shiro的配置说明

Apache Shiro的配置主要分为四部分: SecurityManager的配置 URL过滤器的配置 静态用户配置 静态角色配置 其中,由于用户.角色一般由后台进行操作的动态数据,比如通过@RequiresRoles注解控制某方法的访问,因此Shiro配置一般仅包含前两项的配置. SecurityManager的配置:  [html] view plaincopy <span style="font-size:18px"><!--shiro securityMan

将 Shiro 作为应用的权限基础 一:shiro的整体架构

将 Shiro 作为应用的权限基础 一:shiro的整体架构 近来在做一个重量级的项目,其中权限.日志.报表.工作量由我负责,工作量还是蛮大的,不过想那么多干嘛,做就是了. 这段时间,接触的东西挺多,比如apacheshiro,spring data,springside.DWZ等,java的东西好多,学过ssh就像当初学过三层一样. 下面看看这个安全框架吧 一.什么是Shiro Shiro是一个强大而灵活的开源安全框架,能够非常清晰的处理认证.授权.管理会话以及密码加密.如下是它所具有的特点:

将 Shiro 作为应用的权限基础 五:密码的加密/解密在Spring中的应用

考虑系统密码的安全,目前大多数系统都不会把密码以明文的形式存放到数据库中. 一把会采取以下几种方式对密码进行处理 密码的存储 "编码"存储 Shiro 提供了 base64和 16 进制字符串编码/解码的 API支持,方便一些编码解码操作. Shiro内部的一些数据的存储/表示都使用了 base64和 16 进制字符串. 下面两端代码分别对其进行演示 Stringstr = "hello"; Stringbase64Encoded = Base64.encodeTo

将 Shiro 作为应用的权限基础 五:SpringMVC+Apache Shiro+JPA(hib

点击链接加入群[JavaEE(SSH+IntelliJIDE+Maven)]:http://jq.qq.com/?_wv=1027&k=L2rbHv 将 Shiro 作为应用的权限基础 五:SpringMVC+Apache Shiro+JPA(hibernate)整合配置 配置web.xml,applicationContext.xml, spring-mvc.xml,applicationContext-shiro.xml,而且都有详细的说明. web.xml是web项目最基本的配置文件,看这

[转]后台页面访问权限:页面基类&amp;内置票据认证 使用方法

本文转自:http://www.cnblogs.com/fishtreeyu/archive/2011/01/29/1947421.html 一般网站后台页面除了登录页面login.aspx未登录用户可访问外,其它页面必须登录用户才可访问, 当用户未登录时进入某个页面则自动判断并跳转到登录页面: (如果login.aspx页面用到图片及Css.Js文件,那么也必须允许未登录用户可访问Images.Css.Js文件夹) 方法一:运用页面基类BasePage.cs 1.BasePage.cs代码:

将 Shiro 作为应用的权限基础 三:基于注解实现的授权认证过程

授权即访问控制,它将判断用户在应用程序中对资源是否拥有相应的访问权限. 如,判断一个用户有查看页面的权限,编辑数据的权限,拥有某一按钮的权限等等. 一.用户权限模型 为实现一个较为灵活的用户权限数据模型,通常把用户信息单独用一个实体表示,用户权限信息用两个实体表示. 用户信息用 LoginAccount 表示,最简单的用户信息可能只包含用户名 loginName 及密码 password 两个属性.实际应用中可能会包含用户是否被禁用,用户信息是否过期等信息. 用户权限信息用 Role 与 Per

将 Shiro 作为应用的权限基础 二:基于SpringMVC实现的认证过程

认证就是验证用户身份的过程.在认证过程中,用户需要提交实体信息(Principals)和凭据信息(Credentials)以检验用户是否合法.最常见的“实体/凭证”组合便是“用户名/密码”组合. 一.认证过程 1.收集实体/凭据信息 Java代码 UsernamePasswordToken token = new UsernamePasswordToken(username, password); token.setRememberMe(true); UsernamePasswordToken支