Shiro权限管理框架

2023-11-18

Shiro

一. Shiro权限

  • 什么是权限控制:
    • 忽略特别细的概念,比如权限能细分很多种,功能权限,数据权限,管理权限等
    • 理解两个概念:用户和资源,让指定的用户,只能操作指定的资源(CRUD)
  • 初学javaweb时怎么做
    • Filter接口中有一个doFilter方法,自己编写好业务Filter,并配置对哪个web资源进行拦截后
    • 如果访问的路径命中对应的Filter,则会执行doFilter()方法,然后判断是否有权限进行访问对应的资源
    • /api/user/info?id=1
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) {
	HttpServletRequest httpRequest=(HttpServletRequest)request;
	HttpServletResponse httpResponse=(HttpServletResponse)response;

	HttpSession session=httpRequest.getSession();

	if(session.getAttribute("username")!=null){
		chain.doFilter(request, response);  //如果可以放行
	} else {
		httpResponse.sendRedirect(httpRequest.getContextPath()+"/login.jsp");
	}
}

二. 权限框架ACL和RBAC

2.1 什么是ACL和RBAC
  • ACL: Access Control List 访问控制列表

    • 以前盛行的一种权限设计,它的核心在于用户直接和权限挂钩
    • 优点:简单易用,开发便捷
    • 缺点:用户和权限直接挂钩,导致在授予时的复杂性,比较分散,不便于管理
    • 例子:常见的文件系统权限设计, 直接给用户加权限
  • RBAC: Role Based Access Control

    • 基于角色的访问控制系统。权限与角色相关联,用户通过成为适当角色的成员而得到这些角色的权限
    • 优点:简化了用户与权限的管理,通过对用户进行分类,使得角色与权限关联起来
    • 缺点:开发对比ACL相对复杂
    • 例子:基于RBAC模型的权限验证框架与应用 Apache Shiro、spring Security
  • BAT企业 ACL,一般是对报表系统,阿里的ODPS

  • 总结:不能过于复杂,规则过多,维护性和性能会下降, 更多分类 ABAC、PBAC等

2.2 主流权限框架介绍和技术选型讲解
  • 什么是 spring Security:官网基础介绍

    Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。它提供了一组可以在Spring应用上下文中配置的Bean,充分利用了Spring IoC,DI(控制反转Inversion of Control ,DI:Dependency Injection 依赖注入)和AOP(面向切面编程)功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作。
    
    一句话:Spring Security 的前身是 Acegi Security ,是 Spring 项目组中用来提供安全认证服务的框架
    
  • 什么是 Apache Shiro:官网基础介绍

    • https://github.com/apache/shiro

      Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码和会话管理。使用Shiro的易于理解的API,您可以快速、轻松地获得任何应用程序,从最小的移动应用程序到最大的网络和企业应用程序。
      
      一句话:Shiro是一个强大易用的Java安全框架,提供了认证、授权、加密和会话管理等功能
      
  • 两个优缺点,应该怎么选择

    • Apache Shiro比Spring Security , 前者使用更简单

    • Shiro 功能强大、 简单、灵活, 不跟任何的框架或者容器绑定,可以独立运行

    • Spring Security 对Spring 体系支持比较好,脱离Spring体系则很难开发

    • SpringSecutiry 支持Oauth鉴权 https://spring.io/projects/spring-security-oauth,Shiro需要自己实现

三. Apache Shiro基础概念和架构

3.1 Shiro核心知识之架构图交互和四大模块
  • 直达Apache Shiro官网 http://shiro.apache.org/introduction.html
  • 什么是身份认证
    • Authentication,身份证认证,一般就是登录
  • 什么是授权
    • Authorization,给用户分配角色或者访问某些资源的权限
  • 什么是会话管理
    • Session Management, 用户的会话管理员,多数情况下是web session
  • 什么是加密
    • Cryptography, 数据加解密,比如密码加解密等

img

3.2 Shrio权限控制流程和概念
  • Subject
    • 我们把用户或者程序称为主体(如用户,第三方服务,cron作业),主体去访问系统或者资源
  • SecurityManager
    • 安全管理器,Subject的认证和授权都要在安全管理器下进行
  • Authenticator
    • 认证器,主要负责Subject的认证
  • Realm
    • 数据域,Shiro和安全数据的连接器,好比jdbc连接数据库; 通过realm获取认证授权相关信息
  • Authorizer
    • 授权器,主要负责Subject的授权, 控制subject拥有的角色或者权限
  • Cryptography
    • 加解密,Shiro的包含易于使用和理解的数据加解密方法,简化了很多复杂的api
  • Cache Manager
    • 缓存管理器,比如认证或授权信息,通过缓存进行管理,提高性能

img

更多资料导航:http://shiro.apache.org/reference.html

四. Spring boot整合Shiro

4.1 依赖
<dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <scope>provided</scope>
</dependency>
<dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>druid</artifactId>
</dependency>
<dependency>
      <groupId>org.apache.shiro</groupId>
      <artifactId>shiro-spring</artifactId>
      <version>1.4.1</version>
</dependency>
    <!-- mybatis分页支持 -->
<dependency>
      <groupId>com.github.pagehelper</groupId>
      <artifactId>pagehelper-spring-boot-starter</artifactId>
      <version>1.2.12</version>
</dependency>
    <!-- tk.mybatis对mybatis做了二次封装-->
<dependency>
      <groupId>tk.mybatis</groupId>
      <artifactId>mapper</artifactId>
      <version>4.1.5</version>
</dependency>
    <!-- tk.mybatis与spring boot整合 -->
<dependency>
      <groupId>tk.mybatis</groupId>
      <artifactId>mapper-spring-boot-starter</artifactId>
      <version>2.1.5</version>
</dependency>
4.2 数据库表的设计

权限标准五张表:

  • sys_user
  • sys_role
  • sys_user_role
  • sys_permission
  • sys_role_permission
4.3 自定义realm
public class CustomRealm extends AuthorizingRealm {

    /**
     * 进行权限校验的时候回调用
     */
 	@Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals){
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        return simpleAuthorizationInfo;
    }

    /**
     * 用户登录的时候会调用
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) 		throws AuthenticationException {
        return new SimpleAuthenticationInfo(username, user.getPassword(), 	
        					this.getClass().getName());
    }
}
4.3 shiro配置
@Configuration
public class ShiroConfig {

    @Bean
    public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager){
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();

        shiroFilterFactoryBean.setSecurityManager(securityManager);

        shiroFilterFactoryBean.setLoginUrl("/no_login");

        shiroFilterFactoryBean.setUnauthorizedUrl("/no_auth");

        Map<String, String> chainFilter = new LinkedHashMap<>();

        chainFilter.put("/login", "anon");  //允许登录

        chainFilter.put("/**", "authc");

        shiroFilterFactoryBean.setFilterChainDefinitionMap(chainFilter);

        return shiroFilterFactoryBean;
    }

    /**
     *  该类的作用是,实现注解的方式来设置权限
     */
    @Bean
    public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator(){
        DefaultAdvisorAutoProxyCreator advisor = new DefaultAdvisorAutoProxyCreator();
        advisor.setProxyTargetClass(true);
        return advisor;
    }
 
 	/**
     * 实现注解的方式来配置权限
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor 
    			authorizationAttributeSourceAdvisor(SecurityManager securityManager){
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new 
        				AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }
    /**
    @Bean
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }
     */

   /**
    *  SecurityManager的配置
    */
    @Bean
    public SecurityManager securityManager(SessionManager manager, Realm realm) 	{
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setSessionManager(sessionManager);
        securityManager.setRealm(realm);
        return securityManager;
    }

   /**
    *  SessionManager的配置
    */
    @Bean
    public SessionManager sessionManager(){
        SessionManager sessionManager = new CustomSessionManager();
        return sessionManager;
    }


    /**
     * Realm
     * @param addSaltCredentialsMatch
     * @return
     */
    @Bean
    public Realm realm(AddSaltCredentialsMatch addSaltCredentialsMatch) {
        CustomRealm realm = new CustomRealm();
        realm.setCredentialsMatcher(addSaltCredentialsMatch);  //密码规则
        return realm;
    }

    /**
     * 自定义的密码加盐规则
     * @return
     */
    @Bean
    public AddSaltCredentialsMatch addSaltCredentialsMatch() {
        return new AddSaltCredentialsMatch();
    }
}
4.4 自定义SessionManager
public class CustomSessionManager extends DefaultWebSessionManager {

    /**
     * 重写默认的session
     * @param request
     * @param response
     * @return
     */
    @Override
    protected Serializable getSessionId(ServletRequest request, ServletResponse response) {

        String sessionId = WebUtils.toHttp(request).getHeader("token");
        if(null != sessionId) {
            request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE,
                    ShiroHttpServletRequest.COOKIE_SESSION_ID_SOURCE);

            request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, sessionId);
            //automatically mark it valid here.  If it is invalid, the
            //onUnknownSession method below will be invoked and we'll remove the attribute at that time.
            request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE);

            return sessionId;
        }else {
            return super.getSessionId(request, response);
        }
    }
}

五. 权限数据缓存

​ redis作为企业使用最为频繁的中间件,用来缓存各种业务数据,在使用shiro的缓存的时候,课程中还是采用redis来作为缓存中间件。下载地址:https://github.com/MicrosoftArchive/redis/releases

5.1 引入依赖
<dependency>
      <groupId>org.crazycake</groupId>
      <artifactId>shiro-redis</artifactId>
      <version>3.2.3</version>
</dependency>
5.2 配置RedisManager
@Bean
public RedisManager redisManager() {
	RedisManager redisManager = new RedisManager();
	redisManager.setHost("localhost:6379");
	return redisManager;
}
5.3 配置CacheManager
@Bean
public CacheManager cacheManager(RedisManager redisManager) {
	RedisCacheManager cacheManager = new RedisCacheManager();
	cacheManager.setRedisManager(redisManager);
	return cacheManager;
}
5.4 在SecurityManager中加入缓存管理
securityManager.setCacheManager(cacheManager);

六. Session数据的缓存

6.1 配置RedisSessionDao
@Bean
public RedisSessionDAO redisSessionDAO(RedisManager redisManager) {
	RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
	redisSessionDAO.setRedisManager(redisManager);
	return redisSessionDAO;
}
6.2 SessionManager的设置
@Bean
public SessionManager sessionManager(RedisSessionDAO redisSessionDAO){
	CustomSessionManager sessionManager = new CustomSessionManager();
	sessionManager.setSessionDAO(redisSessionDAO);
	return sessionManager;
}

附录:

/**
   shiro内部提供了做两次md5处理。但是得到数据与其他工具类,得到两次md5数据不一致。
 */
@Bean
public CredentialsMatcher credentialsMatcher() {
	HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
	hashedCredentialsMatcher.setHashAlgorithmName("MD5"); //设置加密方式
	hashedCredentialsMatcher.setHashIterations(2);  //作两次md5加密

	return hashedCredentialsMatcher;
}

处理方式:在用户注册的时候,存入密码的时候就按照shiro的规则来储存密码。

new SimpleHash("md5", "123", null, 2).toString() // 将这种处理方式得到的密码存入数据库。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Shiro权限管理框架 的相关文章

  • 读取文件并获取 key=value 而不使用 java.util.Properties

    我正在构建一个 RMI 游戏 客户端将加载一个包含一些键和值的文件 这些键和值将用于多个不同的对象 它是一个保存游戏文件 但我不能为此使用 java util Properties 它符合规范 我必须读取整个文件并忽略注释行和与某些类不相关
  • 指纹奇异点检测

    我正在尝试确定指纹的核心点和增量点 我正在使用庞加莱指数方法 但我无法成功检测到这一点 而且我不明白为什么 First I divide the image in 15x15 blocks then I calculate the x an
  • 如何防止在 CXF Web 服务客户端中生成 JAXBElement

    我正在尝试使用 CXF 创建一个 Web 服务客户端来使用 WCF Web 服务 当我使用 wsdl2java 时 它生成具有 JAXBElement 类型而不是 String 的对象 我读到有关使用 jaxb bindings xml 文
  • 在 Tomcat 上部署 Java Web 项目,无需 WAR 或 EAR

    我有一个 Java Web 项目 Struts Spring 在我的本地主机上完美运行 我必须将其部署在我的网站上 但虚拟主机提供的 Tomcat Manager 界面显示 由于安全原因 它无法上传 WAR 文件 当联系技术支持时 我被告知
  • Java中定义类型后同时初始化多个变量?

    这里需要一些语法方面的帮助 我正在尝试在定义类型后重新初始化多个变量 例如 int bonus sales x y 50 这工作正常 但是我想稍后在程序中将不同的值放入其中一些变量中 但我收到语法错误 bonus 25 x 38 sales
  • 如何在数据库中对 (Java) 枚举进行建模(使用 SQL92)

    您好 我正在使用名为 性别 的列对实体进行建模 在应用程序代码中 性别应该是一个 Java 枚举类型 有 2 个值 男性和女性 知道作为数据类型的枚举不是通用 SQL 语言 92 的一部分 您将如何建模它 数据模型必须是可移植的 以便由多个
  • Maven 目标的默认阶段?

    据我了解 在 Maven 中 插件目标可以附加到生命周期阶段 如果没有定义 默认阶段是什么 根据我的经验 这取决于插件的目标 例如 组装 单个 http maven apache org plugins maven assembly plu
  • FFmpeg 不适用于 android 10,直接进入 onFailure(String message) 并显示空消息

    我在我的一个项目中使用 FFmpeg 进行视频压缩 在 Android 10 Google Pixel 3a 上 对于发送执行的任何命令 它会直接进入 onFailure String message 并显示空消息 所以我在我的应用程序 g
  • 更改 JTextPane 的大小

    我是Java新手 刚刚在StackOverflow中找到了这段代码 ResizeTextArea https stackoverflow com questions 9370561 enabling scroll bars when jte
  • 如何将txt文件添加到你的android项目中? [复制]

    这个问题在这里已经有答案了 我的Android studio版本是1 5 1 显然这个 never 版本没有 txt 文件的 asset 文件夹 您打算如何将这些文件包含到您的项目中 以及如何进一步使用您内部的应用程序 谢谢你的建议 Pro
  • XSLT:我们可以使用abs值吗?

    我想知道在 XSLT 中我们是否可以使用 math abs 我在某处看到过这个 但它不起作用 我有类似的东西
  • 如何列出所有可用的 LookAndFeel 主题?

    如何列出所有可用的 LookAndFeel 主题 我想在 JComboBox 中显示以供用户选择 这真的很简单 public static UIManager LookAndFeelInfo getInstalledLookAndFeels
  • 使用 Cucumber Scenario Outline 处理 Excel 电子表格

    如果可能的话 我试图找到一种更优雅的方法来处理从与 Excel 电子表格行 第 n 个 相关的 Cucumber Scenario Outline 中调用第 n 个数字 目前 我正在使用迭代编号来定义要从中提取数据的 Excel 电子表格的
  • java中wav文件转换为字节数组

    我的项目是 阿塞拜疆语音的语音识别 我必须编写一个程序来转换wav文件到字节数组 如何将音频文件转换为byte 基本上如第一个答案中的片段所描述 但不是BufferedInputStream use AudioSystem getAudio
  • Jenkins 管道和 java.nio.file.* 方法的问题

    我正在尝试使用 java nio file 中的方法在 Jenkins 管道中执行一些基本文件操作 无论代码存在于哪个节点块中 代码都在主节点上执行 在管道中 我已经验证了各个节点块都是正确的 它们唯一地标识了特定的节点 但是 pathEx
  • 如何使用 SAX Java 解析器读取注释文本

    我只想使用 Java 中的 SAX 解析器读取 XML 文件中对象标记的注释 这是我的文件的摘要
  • Java中的媒体播放器库[关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我正在评估用于在 Java 中播放音频 视频的库 它不需要 100 Java Java 与本机库的绑定
  • 编译时在代码中替换Java静态最终值?

    在java中 假设我有以下内容 fileA java class A public static final int SIZE 100 然后在另一个文件中我使用这个值 fileB java import A class b Object t
  • RecyclerView 不调用 onCreateViewHolder 或 onBindView

    没有收到任何错误 所有数据似乎都有效 由于某种原因 没有调用与视图相关的方法 我已确定以下事项 getItemCount 是唯一被调用的适配器方法 并且返回一个正整数值 我知道这将是你们将要查看的区域 构造函数正在被调用 成员变量有效 Pa
  • java中的回调是什么[重复]

    这个问题在这里已经有答案了 可能的重复 什么是回调函数 https stackoverflow com questions 824234 what is a callback function 我已经阅读了回调的维基百科定义 但我仍然没有明

随机推荐

  • flutter 插件

    一 简介 Flutter 中调用这些能力就必须和原生平台进行通信 目前Flutter 已经支持 iOS Android Web macOS Windows Linux等众多平台 要调用特定平台 API 就需要写插件 插件是一种特殊的包 和纯
  • LeetCode234:回文链表

    题目描述 题目链接 请判断一个链表是否为回文链表 示例 1 输入 1 gt 2 输出 false 示例 2 输入 1 gt 2 gt 2 gt 1 输出 true 进阶 你能否用 O n 时间复杂度和 O 1 空间复杂度解决此题 解题思路
  • 贪吃蛇实验报告

    贪吃蛇实验报告 第一次写博客 这是中山大学软件工程导论的项目之一 对初学者可能有点难度 分享出来做参考 使用的C语言 如果你喜欢的话可以使用 就这样 直接上代码 智能蛇部分也发上来 include
  • 实现二维数组或多维数组排序得方法

    例 对数组 3 2 6 2 3 6 3 4 5 3 进行排序 方法一 import numpy as np a np array 3 2 6 2 3 6 3 4 5 3 ind np lexsort a 1 a 0 print a ind
  • Linux- 文件夹相关的常用指令

    1 统计文件夹下的文件数量 在 Linux 下 有几种方法可以统计文件夹下的文件数量 使用 ls 和 wc 命令 这种方式可以统计目录下的直接子文件 不包括子目录里的文件 ls l lt 目录路径 gt wc l 注意 这将也统计目录自身
  • Hugging Face PEFT 调优实战附代码

    Hugging Face PEFT 调优实战附代码 PEFT调优大模型 Hugging Face PEFT 调优实战附代码 使用Hugging Face PEFT Library 先快速上手使用PEFT LoRA详解 实际应用 Kaggle
  • 常见的Web漏洞——命令注入

    目录 命令注入简介 命令注入原理 漏洞利用 漏洞防范 总结 命令注入简介 命令注入漏洞和SQL注入 XSS漏洞很相似 也是由于开发人员考虑不周造成的 在使用web应用程序执行系统命令的时候对用户输入的字符未进行过滤或过滤不严格导致的 常发生
  • RBF网络的matlab实现

    一 用工具箱实现函数拟合 参考 http blog csdn net zb1165048017 article details 49407075 1 newrb 该函数可以用来设计一个近似径向基网络 approximate RBF 调用格式
  • python教程30-python2和python3的区别、is和isinstance的使用、字类重写父类方法、不使用多态的问题、多态的使用

    python教程 小白入门2021 4 19 学习目标 这里是对应的视频链接 目录 python教程 小白入门2021 4 49 P173 python2和python3的区别 P174 is和isinstance的使用 P175 子类重写
  • 第十三节:特殊的对象——数组的详解

    typeof null 为什么结果是Object JS解释器编译原则 如果二进制前三位是0 typeof查询的数据类型返回的就是Object 而null转换为二进制存储时 全部位数均为0 所以typeof查询结果为Object 这是早期开发
  • 计算机网络——传输层

    一 传输层概述 传输层功能 完成主机进程 主机进程之间的报文传输 传输层是真正的端对端的通信 传输层协议在端主机上运行 路由器一般没有传输层 传输层从主机层面上对网络层采取相应补救措施 可以提供更高质量的数据传输能力 传输层独立于网络设备
  • 设计模式——Visitor(访问者)模式

    目录 前言 1 定义 2 适用性 3 结构 3 1 结构图 3 2 参与者 4 Java实际应用举例 以ASM技术为例 4 1 被访问对象 ClassReader 4 2 Visitor ClassVisitor 4 3 具体visitor
  • web渗透测试学习路线

    web渗透学习路线 文章目录 web渗透学习路线 前言 一 web渗透测试是什么 二 web渗透步骤 1 前期工作 2 中期提高 3 后期打牢 总结 前言 本文整理的学习路线 清晰明了 重点分明 能快速上手实践 相信想学的同学们都能轻松学完
  • Stable Diffusion入门笔记(自用)

    学习视频 20分钟搞懂Prompt与参数设置 你的AI绘画 咒语 学明白了吗 零基础入门Stable Diffusion 保姆级新手教程 Prompt关键词教学 哔哩哔哩 bilibili 1 图片提示词模板 2 权重 提示词 无数字 fl
  • 如何编译火狐浏览器的源代码

    以下摘录于 http zhidao baidu com question 33214960 html 源代码编译安装Firefox linux下 http forums mozine cn index php showtopic 601 W
  • Goland2023版新UI的debug模式调试框按钮功能说明

    一 背景 Jetbrains家的IDE的UI基本都是一样的 debug模式的调试框按钮排列也是一致的 但是在我使用Goland2023版的新UI时 发现调试框的按钮变化还是很大的 有一些按钮被收起来了 如果看之前的博客会发现有一些文中的旧U
  • 自绘CComboBox

    转自 http www gymsaga com mfc 419 html 先介绍基本ComboBox 风格 列表框何时可见 静态控件还是编辑控件 Simple 包括下拉框一直可见 编辑控件 Drop down 可编辑 下拉框 点击可见 编辑
  • 数字逻辑笔记7丨2.5逻辑函数卡诺图化简法

    卡诺图的构成 1 卡诺图的构成 一种图形化简法 在逻辑设计中广泛应用 卡诺图 一种平面方格图 每个小方格代表一个最小项 又叫 最小项方格图 卡诺图可以视为真值表图形化的结果 n个变量的真值表是用2的n次方行给出变量的2的n次方种取值 每行取
  • laravel框架 - 安装初步使用学习 composer安装

    一 什么是laravel框架 Laravel框架可以开发各种不同类型的项目 内容管理系统 Content Management System CMS 是一种比较典型的项目 常见的网站类型 如门户 新闻 博客 文章等 都可以利用CMS进行搭建
  • Shiro权限管理框架

    Shiro 一 Shiro权限 什么是权限控制 忽略特别细的概念 比如权限能细分很多种 功能权限 数据权限 管理权限等 理解两个概念 用户和资源 让指定的用户 只能操作指定的资源 CRUD 初学javaweb时怎么做 Filter接口中有一