• 史诗级的SpringSecurity的认证授权的相关概念及流程讲解!!!


    前言

    Web应用的开发,安全是至关重要的,选择使用SpringSecurity是目前来说较为正确的选择。SpringSecurity框架起源于2003年年底acegi系统,起因是 Spring开发者邮件列表中的一个问题,有人提问是否考虑提供一个基于Spring的安全实现。

    基于SpringBoot+MP+Redis+Vue实现的前后端分离的权限管理系统
    https://gitee.com/xwrich/authority

    一、SpringSecurity简介

    Spring 是非常流行和成功的 Java 应用开发框架,而Spring Security 正是其中的一员。Spring Security 基于 Spring 框架,提供了一套 Web 应用安全性的完整解决方案。
    关于安全方面的两个核心功能是“认证”和“授权”,一般来说,Web 应用的安全性包括**用户认证(Authentication)和用户授权(Authorization)**两个部分,这两点也是 SpringSecurity 重要核心功能。
    (1)用户认证:验证某个用户是否为系统中的合法主体,也就是说用户能否访问该系统。用户认证一般要求用户提供用户名和密码,系统通过校验用户名和密码来完成认证过程。
    (2)用户授权:验证某个用户是否有权限执行某个操作。在一个系统中,不同用户所具有的权限是不同的。比如对一个文件来说,有的用户只能进行读取,而有的用户可以进行修改。一般来说,系统会为不同的用户分配不同的角色,而每个角色则对应一系列的权限。

    二、Shiro和Security的对比

    2.1 Shiro的特点

    • 轻量级。主张的理念是把复杂的事情变简单。针对对性能有更高要求的互联网应用有更好表现。
    • 通用性。不局限于 Web 环境,可以脱离 Web 环境使用。
    • 依赖性低。不需要任何框架和容器,可以独立运行
    • 配置和使用比较简单

    Shiro的三个核心组件:Subject、SecurityManager 和 Realms。

    2.2 Security的特点

    • 全面的权限控制。
    • 专门为 Web 开发而设计。
    • Spring Security 依赖Spring容器
    • 新版本对整个框架进行了分层抽取,分成了核心模块和 Web 模块。单独引入核心模块就可以脱离 Web 环境。

    2.3 二者的相同点

    • 认证功能
    • 授权功能
    • 加密功能
    • 会话管理
    • 缓存支持
    • rememberMe功能

    基于以上,一般来说,常见的安全管理技术栈的组合是这样的:

    • SSM + Shiro
    • Spring Boot/Spring Cloud + Spring Security

    三、Security实现权限

    若要对Web资源进行保护,最好的办法是使用Filter对方法调用进行保护,当然也可以使用AOP的方式。
    Spring Security进行认证和鉴权的时候,就是利用的一系列的Filter来进行拦截的。
    在这里插入图片描述一个请求想要访问到API就会从左到右经过蓝线框里的过滤器,其中绿色部分是负责认证的过滤器蓝色部分是负责异常处理橙色部分则是负责授权。进过一系列拦截最终访问到我们的API。

    这里面我们只需要重点关注两个过滤器即可:UsernamePasswordAuthenticationFilter负责登录认证FilterSecurityInterceptor负责权限授权

    说明:Spring Security的核心逻辑全在这一套过滤器中,过滤器里会调用各种组件完成功能,掌握了这些过滤器和组件就掌握了Spring Security!这个框架的使用方式就是对这些过滤器和组件进行扩展。

    四、用户认证流程

    在这里插入图片描述
    当前登录用户在Spring Security中的体现就是 Authentication,它存储了认证信息,代表当前登录用户。使用时通过 SecurityContext 来获取AuthenticationSecurityContext就是我们的上下文对象!这个上下文对象则是交由 SecurityContextHolder 进行管理。你可以这样使用:

    Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
    
    • 1

    SecurityContextHolder原理非常简单,就是使用ThreadLocal来保证一个线程中传递同一个对象。

    Spring Security中三个核心组件:
    1、Authentication:存储了认证信息,代表当前登录用户
    ​2、SeucirtyContext:上下文对象,用来获取Authentication
    3、SecurityContextHolder:上下文管理对象,用来在程序任何地方获取SecurityContext

    Authentication中的信息包含:
    1、Principal:用户信息,没有认证时一般是用户名,认证后一般是用户对象
    2、Credentials:用户凭证,一般是密码
    ​3、Authorities:用户权限

    Spring Security用户认证关键代码

    // 生成一个包含账号密码的认证信息
    Authentication authenticationToken = new UsernamePasswordAuthenticationToken(username, passwrod);
    // AuthenticationManager校验这个认证信息,返回一个已认证的Authentication
    Authentication authentication = authenticationManager.authenticate(authenticationToken);
    // 将返回的Authentication存到上下文中
    SecurityContextHolder.getContext().setAuthentication(authentication);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    4.1 认证接口分析

    AuthenticationManager的校验逻辑:
    根据用户名先查询出用户对象(没有查到则抛出异常),将用户对象的密码和传递过来的密码进行校验,密码不匹配则抛出异常。

    根据用户名查询出用户对象交由UserDetialsService接口处理,该接口只有一个方法loadUserByUsername(String username),通过用户名查询用户对象,默认实现是在内存中查询。

    查询出来的用户对象需要通过Spring Security中的用户数据UserDetails 实体类来体现,该接口中提供了账号、密码等通用属性。

    对密码进行校验使用PasswordEncoder组件,负责密码加密与校验。

    看下AuthenticationManager校验逻辑的大概源码:

    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
    ...省略其他代码
    
        // 传递过来的用户名
        String username = authentication.getName();
        // 调用UserDetailService的方法,通过用户名查询出用户对象UserDetail(查询不出来UserDetailService则会抛出异常)
        UserDetails userDetails = this.getUserDetailsService().loadUserByUsername(username);
        String presentedPassword = authentication.getCredentials().toString();
    
        // 传递过来的密码
        String password = authentication.getCredentials().toString();
        // 使用密码解析器PasswordEncoder传递过来的密码是否和真实的用户密码匹配
        if (!passwordEncoder.matches(password, userDetails.getPassword())) {
            // 密码错误则抛出异常
            throw new BadCredentialsException("错误信息...");
        }
    
        // 这里返回的已认证Authentication,是将整个UserDetails放进去充当Principal
        UsernamePasswordAuthenticationToken result = new UsernamePasswordAuthenticationToken(userDetails,
                authentication.getCredentials(), userDetails.getAuthorities());
        return result;
    
    ...省略其他代码
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    UserDetialsServiceUserDetailsPasswordEncoder,这三个组件Spring Security都有默认实现,但是满足不了我们的实际需求,所以需要我们自己来实现这些组件。

  • 相关阅读:
    rancher2.6.4配置管理k8s,docker安装
    layui table列表重载后保持进度条位置不变
    Burp Suite 扫描工具
    leetcode 547.省份数量 并查集
    嵌入式开发没有激情了,正常吗?
    读书笔记-你不知道的js(中卷)
    excel+requests管理测试用例接口自动化框架
    链设计模式-装饰模式、职责链设计模式
    Vue学习笔记
    计算机竞赛 深度学习+python+opencv实现动物识别 - 图像识别
  • 原文地址:https://blog.csdn.net/qq_44723773/article/details/127797721