今天发现一个问题:使用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

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

  1. 基于权限安全框架Shiro的登录验证功能实现

    目前在企业级项目里做权限安全方面喜欢使用Apache开源的Shiro框架或者Spring框架的子框架Spring Security. Apache Shiro是一个强大且易用的Java安全框架,执行身 ...

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

    序: 在上一篇中,咱们已经对于项目已经做了基本的配置,这一篇文章开始学习Shiro如何对登录进行验证. 教学: 一.Shiro配置的简要说明. 有心人可能注意到了,在上一章的applicationCo ...

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

    1 课程计划 1. 常见权限控制方式 2. 基于shiro提供url拦截方式验证权限 3. 在realm中授权 4. 基于shiro提供注解方式验证权限 5. 总结验证权限方式(四种) 6. 用户注销 ...

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

    将 Shiro 作为应用的权限基础 一:shiro的整体架构 近来在做一个重量级的项目,其中权限.日志.报表.工作量由我负责,工作量还是蛮大的,不过想那么多干嘛,做就是了. 这段时间,接触的东西挺多, ...

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

    本文转自:http://www.cnblogs.com/fishtreeyu/archive/2011/01/29/1947421.html 一般网站后台页面除了登录页面login.aspx未登录用户 ...

  6. 使用Mongodb+Shiro+SpringMVC实现动态权限分配

    此次的文档只对Mongodb整合Shiro并且实现动态权限分配做整理,其它的内容以后会补上. 第一步.创建在web.xml中配置 Spring .Shiro shiroFilter 过滤器是用来将请求 ...

  7. spring boot(十四)shiro登录认证与权限管理

    这篇文章我们来学习如何使用Spring Boot集成Apache Shiro.安全应该是互联网公司的一道生命线,几乎任何的公司都会涉及到这方面的需求.在Java领域一般有Spring Security ...

  8. 将 Shiro 作为应用的权限基础 二:shiro 认证

    认证就是验证用户身份的过程.在认证过程中,用户需要提交实体信息(Principals)和凭据信息(Credentials)以检验用户是否合法.最常见的“实体/凭证”组合便是“用户名/密码”组合. 一. ...

  9. ecshop 管理后台菜单及权限管理机制

    ecshop 所有的一级菜单选项存放于languages\zh_cn\admin\common.php 文件里面,使用 $_LANG['02_cat_and_goods'] = '商品管理';  这样 ...

随机推荐

  1. DeBruijin HDU - 2894(????????)

    题意: 莫名其妙 看不懂..只能靠别人的题意混日子 a完就懂了  就是 POJ1392  不求第k个了  直接输出这个路径 emm ...就改了一下那个代码 #include <iostream ...

  2. day9 字符串格式化输出 % .format()

    常用的格式化输出方式1 % 方式 print("i am %s my hobby is %s" %("yt","eat")) 打印浮点数,. ...

  3. 集成源码深度剖析:Fescar x Spring Cloud

    Fescar 简介 常见的分布式事务方式有基于 2PC 的 XA (e.g. atomikos),从业务层入手的 TCC( e.g. byteTCC).事务消息 ( e.g. RocketMQ Hal ...

  4. 22 Zabbix系统版本升级过程

    点击返回:自学Zabbix之路 点击返回:自学Zabbix4.0之路 点击返回:自学zabbix集锦 22 Zabbix系统版本升级过程 Zabbix升级与其他相类似系统升级一样,前提一定做好备份,备 ...

  5. 自学Linux Shell12.8-循环实例

    点击返回 自学Linux命令行与Shell脚本之路 12.8-循环实例 待定. 3 fi bash shell的if语句会运行if后面的那个命令. 如果该命令的退出状态码是0 (该命令成功运行),位于 ...

  6. android限制横竖屏切换 方法

    在需要限制横竖屏切换的时候,只需要在AndroidManifest.xml文件中加入android:screenOrientation属性限制. android:screenOrientation=& ...

  7. 【AGC010D】Decrementing

    Solution 日常博弈论做不出来. 首先,数值全部为1的局面先手必败. 在接下来的过程中,我们只关注那些大于1的数值. 按照官方题解的思路,首先想一个简化版的问题:没有除的操作,其余相同.那么局面 ...

  8. CAN总线疑惑与解答

    1    CAN总线2根数据线是怎么表示数据信息1和0的? Can总线采用差分数据表示方法,平时2个数据线为2.5V,表示隐性(1).当用数据0(显性)需要发送时1跟数据线上升到3.5V另一个下降到1 ...

  9. P1856 矩形周长

    哇!这小破题坑了我好久. 扫描线+线段树 这题数据范围小,没离散化.真要离散化我还搞不好呢. 具体的看这个博客吧. 主要是这个坑爹的c,len把我搞了,其他的还好. 代码: #include < ...

  10. 解决FLASH遮住层的问题 IE,Firefox都适用!

    <object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://down ...