Shiro和Spring Sercurity应该是我们比较常用的权限框架了,这篇文章教大家怎么通过springboot整合shiro从0开始搭建一个包含权限控制的后台管理系统。
第一步:创建一个springboot项目
创建springboot项目,这里项目就命名为shiro
第二步:pom.xml中添加maven的依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.9</version>
        <relativePath/>
    </parent>
    <groupId>com.example</groupId>
    <artifactId>shiro</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <properties>
        <java.version>1.8</java.version>
        <shiro.version>1.3.2</shiro.version>
        <mysql.version>8.0.28</mysql.version>
        <druid.version>1.1.21</druid.version>
        <lombok.version>1.18.22</lombok.version>
        <fastjson.version>2.0.8</fastjson.version>
        <mybatis-boot.version>2.2.2</mybatis-boot.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>${lombok.version}</version>
        </dependency>
        <!--mysql-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${mysql.version}</version>
        </dependency>
        <!--mybatis-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>${mybatis-boot.version}</version>
        </dependency>
        <!--druid-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>${druid.version}</version>
        </dependency>
        <!--fastjson-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>${fastjson.version}</version>
        </dependency>
        <!-- shiro -->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>${shiro.version}</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>第三步:修改系统的配置文件application.yml
spring:
  # 激活profiles配置
  profiles:
    active: dev
  servlet:
    multipart:
      # 文件上传大小设置
      max-file-size: 1024MB
      max-request-size: 1024MB
# mybatis的mapper.xml文件的位置
mybatis:
  mapper-locations: classpath:mapper/*Mapper.xmlapplication-dev.yml
spring:
  # 配置数据源
  datasource:
    username: root
    password: root
    url: jdbc:mysql://localhost:3306/shiro
    driver-class-name: com.mysql.cj.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource
  # 只返回不为null的数据
  jackson:
    default-property-inclusion: non_null
# 设置启动端口号
server:
  port: 8080第四步:新建数据库shiro,创建权限管理的五张表
/*
 Navicat Premium Data Transfer
 Source Server         : MariaDB
 Source Server Type    : MariaDB
 Source Server Version : 100605 (10.6.5-MariaDB)
 Source Host           : localhost:3306
 Source Schema         : shiro
 Target Server Type    : MariaDB
 Target Server Version : 100605 (10.6.5-MariaDB)
 File Encoding         : 65001
 Date: 02/07/2023 20:58:37
*/
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for permission
-- ----------------------------
DROP TABLE IF EXISTS `permission`;
CREATE TABLE `permission`  (
  `id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '名称',
  `type` tinyint(3) UNSIGNED NOT NULL COMMENT '权限类型(父权限/子权限)',
  `url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '接口路径',
  `method` tinyint(3) UNSIGNED NOT NULL DEFAULT 0 COMMENT '请求方式(0-get;1-post)',
  `service` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'mhxysy' COMMENT '服务名',
  `parent_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '父级权限id',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '系统权限表' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of permission
-- ----------------------------
-- ----------------------------
-- Table structure for role
-- ----------------------------
DROP TABLE IF EXISTS `role`;
CREATE TABLE `role`  (
  `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
  `name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '名称',
  `description` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '描述',
  `sort` int(10) UNSIGNED NULL DEFAULT 0 COMMENT '自定义排序序号',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 7 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '系统角色表' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of role
-- ----------------------------
INSERT INTO `role` VALUES (1, '超级管理员', '最高权限,拥有系统所有权限', 0);
INSERT INTO `role` VALUES (2, '系统管理员', '拥有系统设置相关权限', 100);
-- ----------------------------
-- Table structure for role_permission
-- ----------------------------
DROP TABLE IF EXISTS `role_permission`;
CREATE TABLE `role_permission`  (
  `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
  `role_id` int(10) UNSIGNED NOT NULL COMMENT '角色id',
  `permission_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '权限id',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '角色-权限关联表' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of role_permission
-- ----------------------------
-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user`  (
  `id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '姓名',
  `username` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '用户名',
  `password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '12345' COMMENT '密码',
  `phone` varchar(11) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '手机号',
  `gender` tinyint(4) UNSIGNED NOT NULL COMMENT '性别,数据来源于性别代码表(gender)的主键',
  `is_enable` tinyint(4) UNSIGNED NOT NULL COMMENT '是否启用(0-未启用;1-启用中)',
  `last_login_time` datetime NULL DEFAULT NULL COMMENT '上一次登录时间',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '用户表' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES ('2023', '系统管理员', 'system', '', '18888888888', 2, 1, '2022-11-25 00:15:42');
INSERT INTO `user` VALUES ('mhxy1218', '沐雨橙风ιε', 'mumu', 'mhxy1218', '16666666666', 1, 1, '2023-07-02 00:00:29');
-- ----------------------------
-- Table structure for user_role
-- ----------------------------
DROP TABLE IF EXISTS `user_role`;
CREATE TABLE `user_role`  (
  `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
  `role_id` int(10) UNSIGNED NOT NULL COMMENT '角色id,数据来源于role表的主键',
  `user_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '用户id,数据来源于user表的主键',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 6 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '用户-角色关系表表' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of user_role
-- ----------------------------
INSERT INTO `user_role` VALUES (1, 1, 'mhxy1218');
INSERT INTO `user_role` VALUES (2, 3, '2023');
SET FOREIGN_KEY_CHECKS = 1;
第五步:创建5张表对应的实体类、mapper、service和controller,以及mapper.xml
可以在启动类或者配置类上使用注解@MapperScan开启mapper包扫描
@MapperScan("com.example.shiro.mapper")第六步:创建UserRealm
项目根目录下创建realm包,在realm包下创建UserRealm.java,并继承AuthorizingRealm
package com.example.shiro.realm;
import com.example.shiro.entity.User;
import com.example.shiro.exception.GlobalException;
import com.example.shiro.mapper.UserMapper;
import com.example.shiro.restful.ResponseCode;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
 * @author heyunlin
 * @version 1.0
 */
@Component
public class UserRealm extends AuthorizingRealm {
    private final UserMapper mapper;
    @Autowired
    public UserRealm(UserMapper mapper) {
        this.mapper = mapper;
    }
    /**
     * 认证
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        // 得到用户名
        String username = token.getUsername();
        // 根据用户名查询用户信息
        User user = mapper.selectByUsername(username);
        if (user == null) {
            throw new GlobalException(ResponseCode.BAD_REQUEST, "登录失败,用户不存在~");
        }
        if (user.getIsEnable()) {
            String password = new String(token.getPassword());
            if (user.getPassword().equals(password)) {
                return new SimpleAuthenticationInfo(user, password, username);
            }
        }
        return null;
    }
    /**
     * 授权
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        return null;
    }
}第七步:创建Shiro的配置类
项目根目录下创建config包,在config包下创建ShiroConfig.java
package com.example.shiro.config;
import com.example.shiro.realm.UserRealm;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.LinkedHashMap;
import java.util.Map;
/**
 * shiro配置类
 */
@Configuration
public class ShiroConfig {
    /**
     * 配置安全管理器
     * @param userRealm UserRealm
     * @return DefaultWebSecurityManager
     */
    @Bean(name = "securityManager")
    public DefaultWebSecurityManager securityManager(@Qualifier("userRealm") UserRealm userRealm) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(userRealm);
        return securityManager;
    }
    /**
     * 配置Shiro过滤器工厂
     * @param securityManager 安全管理器
     * @return ShiroFilterFactoryBean
     */
    @Bean
    public ShiroFilterFactoryBean shiroFilter(@Qualifier("securityManager") DefaultWebSecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        // 注册安全管理器
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        // 当用户访问认证资源的时候,如果用户没有登录,那么就会跳转到该属性指定的页面
        shiroFilterFactoryBean.setLoginUrl("/login.html");
        // 定义资源访问规则
        Map<String, String> map = new LinkedHashMap<>();
        map.put("/", "authc");
        map.put("/html/*", "authc");
        map.put("/index.html", "authc");
        // 登录接口不需要鉴权
        map.put("/user/login", "anon");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
        return shiroFilterFactoryBean;
    }
}经过以上步骤之后,整个项目的包结构如下

第八步:实现用户登录功能
在UserController类中添加一个login()方法,使用UserLoginDTO对象接收前端传来的用户名和密码。
package com.example.shiro.controller;
import com.example.shiro.dto.UserLoginDTO;
import com.example.shiro.restful.JsonResult;
import com.example.shiro.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
/**
 * @author heyunlin
 * @version 1.0
 */
@RestController
@RequestMapping(path = "/user", produces = "application/json;charset=utf-8")
public class UserController {
    private final UserService service;
    @Autowired
    public UserController(UserService service) {
        this.service = service;
    }
    @RequestMapping(path = "/login", method = RequestMethod.POST)
    public JsonResult<Void> login(UserLoginDTO loginDTO) {
        service.login(loginDTO);
        return JsonResult.success();
    }
}UserServiceImpl中实现用户登录的业务代码,当我们调用Subject的login()方法时,会执行UserRealm下面的认证方法doGetAuthenticationInfo()
package com.example.shiro.service.impl;
import com.example.shiro.dto.UserLoginDTO;
import com.example.shiro.entity.User;
import com.example.shiro.exception.GlobalException;
import com.example.shiro.mapper.UserMapper;
import com.example.shiro.restful.ResponseCode;
import com.example.shiro.service.UserService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
/**
 * @author heyunlin
 * @version 1.0
 */
@Service
public class UserServiceImpl implements UserService {
    private final UserMapper mapper;
    @Autowired
    public UserServiceImpl(UserMapper mapper) {
        this.mapper = mapper;
    }
    @Override
    public void login(UserLoginDTO loginDTO) {
        String username = loginDTO.getUsername();
        // 查询用户信息
        User user = mapper.selectByUsername(username);
        if (user != null) {
            // 如果用户被锁定,提前退出
            if (user.getIsEnable()) {
                // shiro登录认证
                UsernamePasswordToken token = new UsernamePasswordToken(username, loginDTO.getPassword());
                Subject subject = SecurityUtils.getSubject();
                subject.login(token);
                // 设置session失效时间:永不超时
                subject.getSession().setTimeout(-1001);
                // 修改管理员上一次登录时间
                user.setLastLoginTime(LocalDateTime.now());
                mapper.updateById(user);
            } else {
                throw new GlobalException(ResponseCode.FORBIDDEN, "账号已被锁定,禁止登录!");
            }
        } else {
            throw new GlobalException(ResponseCode.NOT_FOUND, "用户名不存在~");
        }
    }
}第九步:创建几个简单的页面试一下效果
准备工作:在resources目录下创建static目录,存放静态资源文件,在static目录下创建js和html目录,把jquery复制到js目录下。
static目录下创建一个登录页面login.html
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8" />
        <title>登录页面</title>
    </head>
    <body>
        <form id="loginForm">
            <table>
                <tr>
                    <td>用户名</td>
                    <td><input id="username" /></td>
                </tr>
                <tr>
                    <td>密码</td>
                    <td><input type="password" id="password" /></td>
                </tr>
                <tr>
                    <td>
                        <button type="button" id="login">登录</button>
                    </td>
                    <td>
                        <button type="reset">重置</button>
                    </td>
                </tr>
            </table>
        </form>
        <script src="/js/jquery.min.js"></script>
        <script src="/js/login.js"></script>
    </body>
</html>js目录下创建login.js,点击登录按钮时提交用户的数据到接口/user/login,完成登录操作
$(document).ready(function () {
    $("#login").click(function () {
        let username = $("#username").val();
        let password = $("#password").val();
        $.post("/user/login", {
            username: username,
            password: password
        }, function (res) {
           if (res.code === 200) {
               location.href = "/html/home.html";
           }
        });
    });
});当我们访问localhost:8080/login.html时,输入mumu/mhxy1218,点击登录时,会跳转到/html/home.html。然后我们清空浏览器缓存,刷新以下页面,发现跳回了/login.html。这是因为在shiro配置类里配置了html目录下所有的资源都要身份认证之后才能访问。
map.put("/html/*", "authc");
第十步:实现授权
接下来,讲解如何通过shiro完成鉴权,在UserRealm里的doGetAuthorizationInfo()方法中实现鉴权的代码,查询用户的权限保存到shiro中,为了方便演示效果,我们模拟几条数据。
package com.example.shiro.realm;
import com.example.shiro.entity.User;
import com.example.shiro.exception.GlobalException;
import com.example.shiro.mapper.UserMapper;
import com.example.shiro.restful.ResponseCode;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.HashSet;
import java.util.Set;
/**
 * @author heyunlin
 * @version 1.0
 */
@Component
public class UserRealm extends AuthorizingRealm {
    private final UserMapper mapper;
    @Autowired
    public UserRealm(UserMapper mapper) {
        this.mapper = mapper;
    }
    /**
     * 认证
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        // 得到用户名
        String username = token.getUsername();
        // 根据用户名查询用户信息
        User user = mapper.selectByUsername(username);
        if (user == null) {
            throw new GlobalException(ResponseCode.BAD_REQUEST, "登录失败,用户不存在~");
        }
        if (user.getIsEnable()) {
            String password = new String(token.getPassword());
            if (user.getPassword().equals(password)) {
                return new SimpleAuthenticationInfo(user, password, username);
            } else {
                throw new GlobalException(ResponseCode.BAD_REQUEST, "用户名或密码错误,登录失败!");
            }
        }
        return null;
    }
    /**
     * 授权
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        User user = (User) principals.getPrimaryPrincipal();
        String username = user.getUsername();
        // todo 通过用户名获取用户的权限
        Set<String> permissions = new HashSet<>();
        permissions.add("/user/delete");
        permissions.add("/user/update");
        authorizationInfo.setStringPermissions(permissions);
        return authorizationInfo;
    }
}在UserController中添加两个方法delete()和update()
package com.example.shiro.controller;
import com.example.shiro.dto.UserLoginDTO;
import com.example.shiro.restful.JsonResult;
import com.example.shiro.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
/**
 * @author heyunlin
 * @version 1.0
 */
@RestController
@RequestMapping(path = "/user", produces = "application/json;charset=utf-8")
public class UserController {
    private final UserService service;
    @Autowired
    public UserController(UserService service) {
        this.service = service;
    }
    @RequestMapping(path = "/login", method = RequestMethod.POST)
    public JsonResult<Void> login(UserLoginDTO loginDTO) {
        service.login(loginDTO);
        return JsonResult.success();
    }
    @RequestMapping(path = "/delete", method = RequestMethod.GET)
    public JsonResult<Void> delete() {
        return JsonResult.success("删除成功");
    }
    @RequestMapping(path = "/update", method = RequestMethod.POST)
    public JsonResult<Void> update() {
        return JsonResult.success("修改成功");
    }
 
}home.html新增两个按钮
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8" />
        <title>系统首页</title>
    </head>
    <body>
        <h1>欢迎来到系统首页!</h1>
        <a href="/user/delete">删除</a> | <button type="button" id="update">修改</button>
    
        <script>
            $(function () {
                $("#update").click(function () {
                    $.post("/user/update", function (res) {
                        if (res.code === 200) {
                            alert(res.message);
                        }
                    });
                });
            });
        </script>
    </body>
</html>自定义过滤器,实现鉴权功能
没有权限访问时抛出异常会有一个问题:过滤器中抛出的异常是不会被统一异常处理器处理的。把抛出异常的代码改成直接返回响应对象JsonResult
package com.example.shiro.filter;
import com.alibaba.fastjson.JSON;
import com.example.shiro.restful.JsonResult;
import com.example.shiro.restful.ResponseCode;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
 * 鉴权过滤器
 * @author heyunlin
 * @version 1.0
 */
@WebFilter("authorizationFilter")
public class AuthorizationFilter implements Filter {
    /**
     * 静态资源文件/文件夹
     */
    private static final List<String> STATIC_RESOURCES;
    static {
        STATIC_RESOURCES = new ArrayList<>();
        STATIC_RESOURCES.add("/index.html");
        STATIC_RESOURCES.add("/login.html");
        STATIC_RESOURCES.add("/images/");
        STATIC_RESOURCES.add("/html/");
        STATIC_RESOURCES.add("/css/");
        STATIC_RESOURCES.add("/js/");
    }
    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        HttpServletRequest request = (HttpServletRequest) req;
        String requestURI = request.getRequestURI();
        if ("/".equals(requestURI) || "/user/login".equals(requestURI)) {
            chain.doFilter(req, resp);
        }
        for (String resource : STATIC_RESOURCES) {
            if (requestURI.contains(resource)) {
                chain.doFilter(req, resp);
            }
        }
        Subject subject = SecurityUtils.getSubject();
        if (subject != null && !subject.isPermitted(requestURI)) {
            HttpServletResponse response = (HttpServletResponse) resp;
            response.setContentType("application/json;charset=utf-8");
            // 构建返回对象
            JsonResult<Void> jsonResult= JsonResult.error(ResponseCode.UNAUTHORIZED, "正在访问未授权的资源~");
            String data = JSON.toJSONString(jsonResult);
            response.getWriter().write(data);
            return;
        }
        chain.doFilter(req, resp);
    }
}好了,文章就分享到这里了,创作不易,如果看完这篇文章感觉对你有所帮助,不要忘了点赞+收藏哦~
文章相关的项目代码已开源,可按需获取:
springboot整合shiro实现认证和授权 https://gitee.com/he-yunlin/shiro.git
https://gitee.com/he-yunlin/shiro.git



















