Spring Security学习

本文最后更新于 2025年7月10日 上午

记录安全框架Spring Security学习

登录校验流程

完整流程


三个过滤器分别是:认证,异常处理,授权

  • 认证流程
  • 登录验证时序图
  • 思路分析
  • 密文格式解析(以$2y$10$开头的标准格式为例):
  • $2y$:算法标识(BCrypt 的版本)。
  • 10:哈希迭代次数(影响加密强度,数值越大越耗时但更安全)。
  • eZ6jT65J5dL6:随机生成的盐值(长度通常为 22 个字符)。

为什么相同明文加密结果不同?

  1. 盐值随机生成
    每次调用 BCryptEncode 时,算法会自动生成一个新的随机盐值。例如,两次加密 “123” 时,盐值可能分别为eZ6jT65J5dL6aB3kL9mN7pQ2,与明文结合后计算的哈希结果自然不同。
  2. 盐值包含在密文中
    密文本身携带了盐值,因此验证密码时无需额外存储盐值 —— 算法会从密文中提取盐值,再与用户输入的密码结合,重新计算哈希并与密文中的哈希值比对。
  • Session无法在集群模式下使用
  • 因为原生 Session 依赖单服务器存储,无法跨服务器共享数据。但通过Session 粘性分布式 Session 存储等方案,可在集群中正常使用 Session,实现用户会话状态的管理。
  • 建议:在现代分布式系统中,优先采用共享存储(如 Redis)实现分布式 Session,既能解决集群环境的兼容性问题,又能提升系统的可扩展性和可靠性。

定义JWT认证过滤器

名词解释

1
2
3
4
public class UsernamePasswordAuthenticationToken extends AbstractAuthenticationToken {  
private static final long serialVersionUID = 550L;
private final Object principal;
private Object credentials;
  • principal:
    表示身份验证的主要标识,比如用户登录时的用户名或用户对象。
    由于它是 final 的,因此在构造函数中初始化之后就不能再改变了,保证了其不可变性。
  • credentials:
    表示身份验证的凭据,例如用户的密码。
    它不是 final 的,意味着可以在后续过程中被修改或清除(例如在认证成功后清除密码)。

三种不同的Ant匹配模式

  1. hello路径下允许所有路径的访问吗
  2. anonymous() 方法用于配置匿名访问规则 ,允许未认证(未登录)的用户以匿名身份访问匹配的 URL 。
    tips:
  • permitAll:完全公开,谁都能看。
  • anonymous:只给没登录的人看,登录后就不能看了。
  • authenticated:必须登录,没登录就不让看。

授权

主要做两件事:

  • 限制访问资源所需权限
  • 将权限封装到authentication中

从数据库中查询权限信息

  • RBAC权限模型
  • 基于角色进行控制
  • 分为五张表张表:用户表、权限表、角色表、用户角色管理表、角色权限管理表
  • 角色表:把权限分为一组一组,不同的角色有不同的权限组,避免用户量大的时候,减少用户表和权限表之间权限管理繁琐
    • 一个角色有多个权限,但一个权限也有多个角色,是一种多对多的关联关系,所以要有一个多对多的角色权限关联表
  • 我自己的感受就是,一个人的所有角色可以用一个字段保存,保存成一个字符串,取出来的时候把不同的角色用不同的符号间隔取出,做一个关联子表的好处可能就是不用在代码层面上间隔取出来,而是转为在数据库中直接查询出所有的数据并且返回为List格式就行了,但是我刚刚ai了一下,多对多的两个表如果不用中间表的话会造成数据的冗余和数据记录数压力大的问题,这跟我一开始对于数据是否在代码层面间隔取出作为list的看法其实并不是重要因素,反而是数据量大的因素更会造成不可估计的系统压力。
  • 这个地方比较难理解的就是关联表维护多对多数据模型的优势
  • 另外权限表一般命名为menu表,可以理解为把所有的功能作为一个菜单保存

自定义异常处理

  1. 继承并实现处理这两个异常处理接口
  2. 添加这两个异常到SecurityConfig中

跨域

  1. 重写spring提供的WebMvcConfigurer接口的addCorsMappings方法
  2. 设置security运行跨域访问

自定义权限校验方法

  1. 自定义表达式组件并给组件命名
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    @Component("aaa")  
    public class MyExpressionRoot {
    public boolean hasAuthority(String authority) {
    // 获取当前用户的权限
    Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
    LoginUser loginUser = (LoginUser) authentication.getPrincipal();
    List<String> permissions = loginUser.getPermissions();
    //判断用户权限集合中是否存在authority
    return permissions.contains(authority);
    }
    }
  2. @组件名进入使用
    1
    2
    3
    4
    5
    @PreAuthorize("@aaa.hasAuthority('system:dept:list')")  
    public String test()
    {
    return "你好世界";
    }
  • 目前authentication中包含的东西

CSRF

  • 跨站请求伪造,web常见攻击
  • 如果不关闭的话,除了校验自己做的token,还会校验CSRF的token

知乎好文讲解

  • 补充:A(service) <— B(serviceImpl)主要是强调一个指向关系(虚线空心箭头),子指向父
  • Principal是谁在访问的“身份标识”,继承他就会贴上一个身份标签,继承后类就会被安全框架自动识别,无需额外配置,主要包含名称、权限、凭证

Spring Security学习
http://yething.github.io/posts/122562275.html
作者
Odyssey
发布于
2025年7月6日
许可协议