Shiro-SpringBoot (二)

news2024/9/28 1:23:08

在上一节中实现了在SpringBoot中使用Shiro做权限控制,但是针对上一节留下的不足点,在这里进行一下优化和改造,主要有一下几点:

  • 支持AJAX请求
  • 支持FreeMarker模板
  • URL拦截提取到yml配置文件

(一) 支持AJAX请求

如果是AJAX请求URL接口,没有登录或是没有权限的时候,我们希望是返回指定的JSON格式,而不是进行页面的重定向。当时这个问题也是困扰很久,好在Shiro在这方面提供了很好的扩展,在google帮助下,我决定使用的方案是重写Shiro提供的Filter过滤器,在没有登录或是角色权限认证失败时进行处理。如果是AJAX请求返回指定JSON,普通请求进行页面的重定向。于是乎我找到如下Shiro Filter的关系图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-anOXjCjW-1669988699578)(https://img-blog.csdn.net/20170601195007717?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdTAxNDA0MjE0Ng==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)]

  • AdviceFilter 过滤器类似于类似于SpringMVC中的HandlerInterceptor拦截器,用于在请求URL之前进行拦截,主要处理一些是否登录的验证
  • PermissionsAuthorizationFilter提供了onAccessDenied方法,主要用于perms资源认证失败时回调onAccessDenied进行一些处理
  • RolesAuthorizationFilter提供了onAccessDenied方法,主要用于roles角色认证失败时回调onAccessDenied进行一些处理

(1) 重写AdviceFilter过滤器

class ShiroAdviceFilter extends AdviceFilter {

    /**
     * 在访问URL前判断是否登录
     * @param request
     * @param response
     * @return true-继续往下执行,false-该filter过滤器已经处理,不继续执行其他过滤器
     * @throws Exception
     */
    @Override
    protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception {
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        HttpServletResponse httpServletResponse = (HttpServletResponse) response;
        User user = (User) httpServletRequest.getSession().getAttribute("user");
        if (null == user && !StringUtils.contains(httpServletRequest.getRequestURI(), "/login")
                && !StringUtils.contains(httpServletRequest.getRequestURI(), "/js")
                && !StringUtils.contains(httpServletRequest.getRequestURI(), "/images")) {
            String requestedWith = httpServletRequest.getHeader("X-Requested-With");
            if (StringUtils.isNotEmpty(requestedWith) && StringUtils.equals(requestedWith, "XMLHttpRequest")) {//如果是ajax返回指定数据
                JSONObject json = new JSONObject();
                json.put("statuscode":500);
                json.put("message":"没有登录");
                httpServletResponse.setCharacterEncoding("UTF-8");
                httpServletResponse.setContentType("application/json");
                httpServletResponse.getWriter().write(JSONObject.toJSONString(json));
                return false;
            } else {//不是ajax进行重定向处理
                httpServletResponse.sendRedirect("/login");
                return false;
            }
        }
        return true;
    }

}

(2) Filter过滤器工具类

public class FilterUtils {

    /**
     * 如果是ajax返回指定格式数据,如果是普通请求重定向页面
     * @param servletRequest
     * @param servletResponse
     * @throws IOException
     */
    public static void AuthorizationOnAccessDenied(ServletRequest servletRequest, ServletResponse servletResponse) throws IOException {
        HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
        HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse;
        String requestedWith = httpServletRequest.getHeader("X-Requested-With");
        if (StringUtils.isNotEmpty(requestedWith) &&
                StringUtils.equals(requestedWith, "XMLHttpRequest")) {//如果是ajax返回指定格式数据
            JSONObject json = new JSONObject();
            json.put("statuscode":403);
            json.put("message":"角色资源认证失败");
            httpServletResponse.setCharacterEncoding("UTF-8");
            httpServletResponse.setContentType("application/json");
            httpServletResponse.getWriter().write(JSONObject.toJSONString(responseHeader));
        } else {//如果是普通请求进行重定向
            httpServletResponse.sendRedirect("/403");
        }
    }

}

(3) 重写PermissionsAuthorizationFilter过滤器

public class ShiroPermsFilter extends PermissionsAuthorizationFilter {

    /**
     * shiro认证perms资源失败后回调方法
     * @param servletRequest
     * @param servletResponse
     * @return
     * @throws IOException
     */
    @Override
    protected boolean onAccessDenied(ServletRequest servletRequest, ServletResponse servletResponse) throws IOException {
        FilterUtils.AuthorizationOnAccessDenied(servletRequest,servletResponse);
        return false;
    }
}

(4) 重写RolesAuthorizationFilter过滤器

public class ShiroRolesFilter extends RolesAuthorizationFilter {
    /**
     * shiro认证roles角色失败后回调方法
     * @param servletRequest
     * @param servletResponse
     * @return
     * @throws IOException
     */
    @Override
    protected boolean onAccessDenied(ServletRequest servletRequest, ServletResponse servletResponse) throws IOException {
        FilterUtils.AuthorizationOnAccessDenied(servletRequest,servletResponse);
        return false;
    }
}

(5) 在上一节Shiro配置类ShiroConfiguration对我们重写的Filter过滤器进行配置,修改如下


    //增加ShiroLoginFilter实例化
    @Bean(name = "shiroLoginFilter")
    public ShiroLoginFilter shiroLoginFilter(){
        ShiroLoginFilter shiroLoginFilter = new ShiroLoginFilter();
        return shiroLoginFilter;
    }

    //修改shiroFilterFactoryBean配置
    @Bean(name = "shiroFilter")
    public ShiroFilterFactoryBean shiroFilterFactoryBean() {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager());
        Map<String, Filter> filtersMap = new LinkedHashMap<String, Filter>();
        filtersMap.put("shiroLoginFilter", shiroLoginFilter());
        filtersMap.put("perms", new ShiroPermsFilter());
        filtersMap.put("roles",new ShiroRolesFilter());
        shiroFilterFactoryBean.setFilters(filtersMap);
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
        //Shiro拦截URL规则
        filterChainDefinitionMap.put("/logout", "logout");
        filterChainDefinitionMap.put("/js/**", "anon");
        filterChainDefinitionMap.put("/css/**", "anon");
        filterChainDefinitionMap.put("/login", "anon");
        filterChainDefinitionMap.put("/403", "anon");
        filterChainDefinitionMap.put("/userInfo/**", "authc,perms[查看用户模块]");
        filterChainDefinitionMap.put("/messageInfo/**", "authc,roles[管理员]");
        filterChainDefinitionMap.put("/**", "authc");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilterFactoryBean;
    }

可以看到我们用的是LinkedHashMap将我们写的ShiroLoginFilter、ShiroPermsFilter、ShiroRolesFilter存储起来并设置。这代表用户每一次URL请求,都会按顺序的经过ShiroLoginFilter -> ShiroPermsFilter -> ShiroRolesFilter处理,只有全部都通过认证才会请求成功,否则将返回JSON或是重定向。这样Shiro既能兼容普通请求的重定向,也能在AJAX时返回JSON,流程图如下:
cmd-markdown-logo

(二) 支持FreeMarker模板

Shiro本身是通提供了JSP的一套标签库,用于在JSP进行权限的控制,对FreeMarker官方是没有提供。但是有大神将其开源到了GitHub,参考shiro-freemarker-tags。下面讲述的是,在SpringBoot项目中使用shiro-freemarker-tags

(1) 在pom.xml中导入依赖

<dependency>
        <groupId>net.mingsoft</groupId>
        <artifactId>shiro-freemarker-tags</artifactId>
        <version>0.1</version>
</dependency>

(2) 新建FreeMarkerConfig类用于配置FreeMarkers标签

@Service
public class FreeMarkerConfig implements InitializingBean {

       @Autowired
       private Configuration configuration;

       @Override
       public void afterPropertiesSet() throws Exception {
           configuration.setSharedVariable("shiro", new ShiroTags());
       }

}

(3) 在FreeMarker页面使用标签库进行权限控制

<@shiro.hasRole name="ADMIN">
    <p>只有ADMIN的角色才能看到这段文字</p>
</@shiro.hasRole>

<@shiro.hasAnyRoles name="admin,user,member">
    <p>只有admin或user或member其中一个角色才能看到这段文字</p>
</@shiro.hasAnyRoles>

<@shiro.lacksRole name="admin">
    <p>只有不拥有admin角色才能看到这段文字</p>
</@shiro.lacksRole>

<@shiro.hasPermission name="查看用户模块">
	<p>只有拥有【查看用户模块】资源的用户才能看到这段文字</p>
</@shiro.hasPermission>

<@shiro.guest>
    您当前是游客,关于更多使用请自行查阅标签库
</@shiro.guest>

(三) URL拦截提取到yml配置文件

之前在ShiroConfiguration配置类的shiroFilterFactoryBean方法中,我们拦截的URL使用LinkedHashMap写在了代码里面,这样后期维护和可观性不够好,我们可以把URL的拦截单独提取到yml配置文件。这里不选择properties文件,是因为properties文件是不支持有序的,这里URL的顺序请务必保持有序的加载。

(1) 在yml文件中配置我们的URL拦截规则

shiro:
    filterUrl:
      /logout: logout
      /js/**: anon
      /css/**: anon
      /images/**: anon
      /login/**: anon
      /logout/**: anon
      /403/**: anon
      /userInfo/**: authc,perms[查看用户模块]
      /messageInfo/**: authc,roles[管理员]
      /**: authc

(2) 新建ShiroUrlStrategy用于从yml加载配置

@EnableConfigurationProperties
@ConfigurationProperties(prefix = "shiro") //yml配置文件的前缀
public class ShiroUrlStrategy {

    private LinkedHashMap<String, String> filterChainDefinitionMap;

    public LinkedHashMap<String, String> getFilterChainDefinitionMap() {
        return filterChainDefinitionMap;
    }

    public void setFilterChainDefinitionMap(LinkedHashMap<String, String> filterChainDefinitionMap) {
        this.filterChainDefinitionMap = filterChainDefinitionMap;
    }
}

(3) 修改ShiroConfiguration配置类

//修改shiroFilterFactoryBean配置
    @Bean(name = "shiroFilter")
    public ShiroFilterFactoryBean shiroFilterFactoryBean() {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager());
        Map<String, Filter> filtersMap = new LinkedHashMap<String, Filter>();
        filtersMap.put("shiroLoginFilter", shiroLoginFilter());
        filtersMap.put("perms", new ShiroPermsFilter());
        filtersMap.put("roles",new ShiroRolesFilter());
        shiroFilterFactoryBean.setFilters(filtersMap);
        //从配置获取URL拦截规则
        ShiroUrlStrategy shiroUrlStrategy = ShiroUrlStrategy();
        LinkedHashMap<String, String> filterChainDefinitionManager = shiroUrlFiler.getFilterChainDefinitionMap();
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionManager);
        return shiroFilterFactoryBean;
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/56003.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

软件外包公司真的去不得吗?

各位小伙伴们&#xff01;好&#xff01;啊&#xff01;最近全国大部分地区都降温了&#xff0c;大家记得做好保暖&#xff0c;不要生病。 无论是应届毕业生&#xff0c;还是准备跳槽的测试人&#xff0c;都有面对“软件外包”公司的可能。有些人说进入外包公司就相当于给履历…

电子招标采购商城系统:优化传统采购业务,提速企业数字化升级

后疫情时代&#xff0c;电子元器件供应链发生了巨大的变化&#xff0c;缺货已经影响了大多数企业&#xff0c;电子元器件采购人员每天被“缺货”“涨价”的字眼包围着&#xff0c;对电子元器件企业的发展带来了极大的限制。当前&#xff0c;借助数字化技术对电子元器件采购管理…

[附源码]计算机毕业设计在线票务系统Springboot程序

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

云服务器和本地服务器的优缺点分析

服务器是企业IT基础设施的命脉&#xff0c;可用于存放文件、应用程序、网站、员工远程访问等等。当然&#xff0c;选择时有许多不同类型的服务器和许多需要考虑的因素。目前比较流行的两种服务器类型是本地服务器和基于云的服务器。 本地服务器 本地服务器放置在公司的办公室中…

VS2022开发Arduino(90%转载10%原创)

先上转载链接 VS2022开发Arduino&#xff08;提供Visual.Micro.Processing.Sketch.dll&#xff09;_hb2cpc的博客-CSDN博客_vs开发arduino Visual Studio 2022开发Arduino详述_liht_1634的博客-CSDN博客_visualstudio arduino 其中破解部分编译出错&#xff0c;此处为原创&am…

RabbitMQ面试篇

文章目录1 你们为什么选择了RabbitMQ而不是其它的MQ&#xff1f;2 RabbitMQ如何确保消息的不丢失&#xff1f;3 RabbitMQ如何避免消息堆积&#xff1f;4 RabbitMQ如何保证消息的有序性&#xff1f;5 如何防止MQ消息被重复消费&#xff1f;6 如何保证RabbitMQ的高可用&#xff1…

计算机体系结构:分支目标缓冲(BTB)例题

题目内容 按照下表计算分支转移总的延迟&#xff0c;根据下面的假设&#xff0c;计算分支目标缓冲的性能。 (1)对于BTB中的指令&#xff0c;预测准确率90%。 (2)缓冲区命令率90%。 (3)不在BTB中分支转移成功的比例为60%。 题目分析 总共有四种情况&#xff1a; ①在BTB中且预…

DSP篇--C6678功能调试系列之网络调试

目录 网络调试 1、GE工程的研究与功能扩充 网络调试 网口测试&#xff0c;使用的是TI官方提供的GE网络测试例程。 主要注意的事项是&#xff1a;时钟的设置、相关设备的MAC地址和IP的设置、中断的设置。确定板子的port和phy。 GbE Switch Subsystem Initialization Procedure…

[附源码]Python计算机毕业设计Django计算机相关专业考研资料管理系统

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

bash调试方法总结

在看nginx源码实现时发现有些代码是根据不同的本地环境动态生成的&#xff0c;看了一下大致生成流程&#xff0c;基本上都是通过shell脚本调用shell脚本实现的。看到了shell脚本&#xff0c;就想到如何调试shell脚本&#xff0c;shell脚本在实际工作中运用的挺多的&#xff0c;…

几何向量:向量到平面投影和LookAt

在研究所保密开发完后回来隔离两波&#xff0c;已经接近四五个月没碰外网电脑了&#xff0c;可以说是活成了原始人。 因为某些开发细节原因&#xff0c;需要实现向量投影和LookAt功能&#xff0c;记录一下。 首先实现向量到平面投影&#xff0c;如下&#xff1a; …

第二证券|鲍威尔发声:释放重磅信号,美股大涨!中概股狂涨

大家早上好&#xff01;昨夜今晨又有许多大事产生&#xff1a;美联储主席鲍威尔证明&#xff0c;12月开端或许放缓加息&#xff1b;微软涨逾1100亿美元&#xff0c;美股进入技能型牛市&#xff1b;小鹏轿车昨日暴升近50%&#xff0c;中概股11月涨逾40%&#xff1b;法、德不满美…

java计算机毕业设计ssm企业日常事务管理系统sl5xl(附源码、数据库)

java计算机毕业设计ssm企业日常事务管理系统sl5xl&#xff08;附源码、数据库&#xff09; 项目运行 环境配置&#xff1a; Jdk1.8 Tomcat8.5 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#…

全栈性能测试教程之性能测试相关知识(二) Jmeter的应用

性能测试相关知识&#xff08;二&#xff09; Jmeter的应 1、性能测试的方法 1.1验收负载测试&#xff1a; 在QA的环境模拟生产运行的业务压力和使用场景组合&#xff0c;测试系统的性能是否满足生产环境的性能诉求。 1.2负载测试 在被测系统上持续不断的增加压力&#xff…

易点易动RFID固定资产管理系统助力企业年终固定资产大盘点

固定资产作为资产构成的重要组成部分&#xff0c;也是企业完成生产经营的物质保障&#xff0c;对企业的发展起着重要的作用。越来越多的企业者开始重视企业内部的固定资产管理&#xff0c;从而会定期对固定资产进行盘点&#xff0c;以保证固定资产账实一致、账账相符。每逢年底…

粒子群算法和鲸鱼算法的比较(Matlab代码实现)

目录 1 粒子群优化算法 2 鲸鱼优化算法 3 粒子群算法和鲸鱼算法比较 4 Matlab代码实现 1 粒子群优化算法 粒子群优化算法(PSO&#xff1a;Particle swarm optimization) 是一种进化计算技术&#xff08;evolutionary computation&#xff09;。源于对鸟群捕食的行为研究…

GitHub限时开源36小时的阿里Java架构师学习手册,上线即标星35k+

前言 今年受大环境影响面试于往年相比难得多&#xff0c;对程序员要求越来越高&#xff01;环境我们无法改变能改变的就是自己&#xff0c;努力提升技术&#xff01; 我在GitHub无意见看见115k的Java教程&#xff0c;感觉还不错&#xff0c;给大家看看&#xff01;文档总共分为…

Cloud Mail JavaScript管理邮件

Cloud Mail JavaScript管理邮件 使用流行的云服务发送、接收和管理邮件。 云邮件使用流行的云服务简化了邮件的发送、接收和管理&#xff0c;包括Amazon SES、Microsoft 365(Outlook Mail)和Gmail。还支持包括OAuth、TLS 1.3和TLS 1.2在内的现代身份验证和安全选项。 云邮件功…

前后端验证码交互完整流程

本文章基于vueelement-uispringbootredis讲解&#xff0c;其他的都是工具&#xff0c;可以直接拿来用&#xff0c;不懂redis没关系&#xff08;因为本文只用了简单的存取&#xff09;&#xff0c;但前面三个要懂 如果你只想看前端或者后端的代码逻辑&#xff0c;本文章同样适用…

提升代码可读性,减少if-else的几个小技巧

前言&#x1f481;‍♂️ 相信大家或多或少都接触过拥有庞大 if else 的项目代码吧&#xff0c;多重嵌套的 if else 在维护的时候真的让人很恼火&#x1f621;&#xff0c;有时候一个 bug 排查下来&#xff0c;严重感觉身体被掏空&#x1f63f;。 本文并未有消灭或歧视 if el…