Spring Security基本源码解析(超精细版)

news2024/12/23 0:07:53

一、基本源码解析

1.1 UsernamePasswordAuthenticationFilter

用户名称和密码的过滤器

浏览器发送用户名称和密码 ----》 经过过滤器「UsernamePasswordAuthenticationFitler」

1.2 UsernamePasswordAuthenticationFilter核心方法

重写父类「AbstractAuthenticationProcessingFilter.java」当中的抽象方法.

@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
    throws AuthenticationException {
    if (this.postOnly && !request.getMethod().equals("POST")) {
        throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
    }
    String username = obtainUsername(request);
    username = (username != null) ? username.trim() : "";
    String password = obtainPassword(request);
    password = (password != null) ? password : "";
    UsernamePasswordAuthenticationToken authRequest = UsernamePasswordAuthenticationToken.unauthenticated(username,password);
    // Allow subclasses to set the "details" property
    setDetails(request, authRequest);
    // 调用认证方法.
    return this.getAuthenticationManager().authenticate(authRequest);
}

1.3 AuthenticationManager「重点」

认证管理器.

this.getAuthenticationManager(), 这里获取的是实现类的对象.

protected AuthenticationManager getAuthenticationManager() {
    return this.authenticationManager;
}
​
public void setAuthenticationManager(AuthenticationManager authenticationManager) {
    this.authenticationManager = authenticationManager;
}

AuthenticationManager接口源码

public interface AuthenticationManager {
    // 核心认证方法.
    // 参数: Authentication, 认证接口
    // 返回值: Authentication, 认证接口
    Authentication authenticate(Authentication authentication) throws AuthenticationException; 
}

实现类

1.4 Authentication接口

认证接口.

// 认证接口.
public interface Authentication extends Principal, Serializable {
    // 获取所有的权限
    Collection<? extends GrantedAuthority> getAuthorities();
    // 用户凭证, 通常这里指的密码.
    Object getCredentials();
    // 存储有关身份验证请求的其他详细信息。这些可能是 IP 地址、证书序列号等。
    Object getDetails();
    // 要进行身份验证的主体的身份。对于带有用户名和密码的身份验证请求,这将是用户名。调用方应填充身份验证请求的主体。
    // AuthenticationManager 实现通常会返回包含更丰富信息的身份验证作为应用程序使用的主体。许多身份验证提供程序将创建一个UserDetails对象作为主体。
    // 返回:
    // Principal被身份验证或身份验证后的身份验证主体。
    Object getPrincipal();
    // 是否已经认证过
    boolean isAuthenticated();
    // 有关完整说明,请参阅 isAuthenticated() 。
    // 实现应 始终 允许使用参数调用 false 此方法,因为各种类使用它来指定不应信任的身份验证令牌。如果实现希望拒绝带有参数的 true 调用(这将指示身份验证令牌受信任 - 潜在的安全风险),则实现应抛出 IllegalArgumentException.
    void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException;
}

1.5 ProviderManager

// AuthenticationManager接口的实现类. 一般情况下都会这东西.
public class ProviderManager implements AuthenticationManager, MessageSourceAware, InitializingBean {
    // 存放各种各样的providers的集合.
    private List<AuthenticationProvider> providers = Collections.emptyList();
 
    // 核心认证方法.
    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        Class<? extends Authentication> toTest = authentication.getClass();
        AuthenticationException lastException = null;
        AuthenticationException parentException = null;
        Authentication result = null;
        Authentication parentResult = null;
        int currentPosition = 0;
        int size = this.providers.size();
        for (AuthenticationProvider provider : getProviders()) {
            if (!provider.supports(toTest)) {
                continue;
            }
            if (logger.isTraceEnabled()) {
                logger.trace(LogMessage.format("Authenticating request with %s (%d/%d)",
                        provider.getClass().getSimpleName(), ++currentPosition, size));
            }
            try {
                // 执行各种各样的认证.
                result = provider.authenticate(authentication);
                if (result != null) {
                    copyDetails(authentication, result);
                    break;
                }
            }
            catch (AccountStatusException | InternalAuthenticationServiceException ex) {
                prepareException(ex, authentication);
                // SEC-546: Avoid polling additional providers if auth failure is due to
                // invalid account status
                throw ex;
            }
            catch (AuthenticationException ex) {
                lastException = ex;
            }
        }
        if (result == null && this.parent != null) {
            // Allow the parent to try.
            try {
                parentResult = this.parent.authenticate(authentication);
                result = parentResult;
            }
            catch (ProviderNotFoundException ex) {
                // ignore as we will throw below if no other exception occurred prior to
                // calling parent and the parent
                // may throw ProviderNotFound even though a provider in the child already
                // handled the request
            }
            catch (AuthenticationException ex) {
                parentException = ex;
                lastException = ex;
            }
        }
        if (result != null) {
            if (this.eraseCredentialsAfterAuthentication && (result instanceof CredentialsContainer)) {
                // Authentication is complete. Remove credentials and other secret data
                // from authentication
                ((CredentialsContainer) result).eraseCredentials();
            }
            // If the parent AuthenticationManager was attempted and successful then it
            // will publish an AuthenticationSuccessEvent
            // This check prevents a duplicate AuthenticationSuccessEvent if the parent
            // AuthenticationManager already published it
            if (parentResult == null) {
                this.eventPublisher.publishAuthenticationSuccess(result);
            }
​
            return result;
        }
​
        // Parent was null, or didn't authenticate (or throw an exception).
        if (lastException == null) {
            lastException = new ProviderNotFoundException(this.messages.getMessage("ProviderManager.providerNotFound",
                    new Object[] { toTest.getName() }, "No AuthenticationProvider found for {0}"));
        }
        // If the parent AuthenticationManager was attempted and failed then it will
        // publish an AbstractAuthenticationFailureEvent
        // This check prevents a duplicate AbstractAuthenticationFailureEvent if the
        // parent AuthenticationManager already published it
        if (parentException == null) {
            prepareException(lastException, authentication);
        }
        throw lastException;
    }
}

1.6 AuthenticationProvider

提供各种认证器.它是一个接口.

public interface AuthenticationProvider {
    // 使用与 相同的 AuthenticationManager.authenticate(Authentication) 协定执行身份验证。
    // 参数:
    // authentication – 身份验证请求对象。
    // 返回:
    // 包含凭据的完全身份验证的对象。如果 无法支持对传递Authentication的对象进行身份验证,则AuthenticationProvider可能返回null。在这种情况下,将尝试下一个AuthenticationProvider支持所呈现Authentication类的方法。
    // 抛出:
    // AuthenticationException – 如果身份验证失败。
    Authentication authenticate(Authentication authentication) throws AuthenticationException;
    
    // 如果支持AuthenticationProvider指示Authentication的对象,则返回true。
    // 返回并不true保证 将AuthenticationProvider能够对所呈现的类实例Authentication进行身份验证。它只是表明它可以支持对它的更仔细的评估。仍然可以从该方法返回 null authenticate(Authentication) can AuthenticationProvider 以指示应尝试另一个AuthenticationProvider方法。
    // 选择能够执行身份验证的在AuthenticationProvider运行时进行。ProviderManager
    // 参数:
    // authentication
    // 返回:
    // true 如果实现可以更仔细地评估所呈现的 Authentication 类
    boolean supports(Class<?> authentication);
}

这里般用的是: DaoAuthenticationProvider.

1.7 UserDetailsService 「重要」

  • 加载用户特定数据的核心界面。它在整个框架中用作用户 DAO,并且是 .DaoAuthenticationProvider该接口只需要一种只读方法,这简化了对新数据访问策略的支持。另请参阅:org.springframework.security.authentication.dao.DaoAuthenticationProvider, UserDetails

public interface UserDetailsService {
    // 根据用户名定位用户。在实际实现中,搜索可能区分大小写或不区分大小写,具体取决于实现实例的配置方式。在这种情况下, UserDetails 返回的对象可能具有与实际请求的用户名不同的大小写。
    // 参数:
    // username – 标识需要其数据的用户的用户名。
    // 返回:
    // 完全填充的用户记录(从不 null)
    // 抛出:
    // UsernameNotFoundException – 如果找不到用户或用户没有授权
    UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
}

1.8 UserDetails 「重要」

实现类是User对象,这个User由spring security提供的.

提供核心用户信息。出于安全目的,Spring 安全性不会直接使用实现。它们只是存储用户信息,这些信息随后封装到对象中 Authentication 。这允许将非安全相关的用户信息(例如电子邮件地址、电话号码等)存储在方便的位置。具体的实现必须特别注意确保强制执行针对每种方法详述的非空协定。有关参考实现(您可能希望在代码中扩展或使用),请参阅 User 。

public interface UserDetails extends Serializable {
​
    /**
     * Returns the authorities granted to the user. Cannot return <code>null</code>.
     * @return the authorities, sorted by natural key (never <code>null</code>)
     */
    Collection<? extends GrantedAuthority> getAuthorities();
​
    String getPassword();
    String getUsername();
    boolean isAccountNonExpired();
    boolean isAccountNonLocked();
    boolean isCredentialsNonExpired();
    boolean isEnabled();
}

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

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

相关文章

MySQL之可扩展性(八)

可扩展性 负载均衡 负载均衡的基本思路很简单:在一个服务器集群中尽可能地平均负载量。通常的做法是在服务器前端设置一个负载均衡器(一般是专门的硬件设备)。然后负载均衡器将请求的连接路由到最空闲的可用服务器。如图显示了一个典型的大型网站负载均衡设置&#xff0c;其中…

昇思25天学习打卡营第4天|常见的数据变换 Transforms类型

导入数据集相关库和模块 首先导入了一些必要的库和模块&#xff0c;包括 numpy&#xff08;np 是其常用的别名&#xff09;、PIL 库中的 Image 模块&#xff0c;以及自定义的 download 模块&#xff0c;还有 mindspore.dataset 中的 transforms、vision、text 模块。然后使用 m…

在预训练语言模型主流架构

文章目录 编码器-解码器架构因果解码器架构前缀解码器架构在预训练语言模型时代,自然语言处理领域广泛采用了预训练 + 微调的范式,并诞生了以 BERT 为代表的编码器(Encoder-only)架构、以 GPT 为代表的解码器(Decoder-only)架构和以 T5 为代表的编码器-解码器(Encoder-d…

springcloud-config服务器,同样的配置在linux环境下不生效

原本在windows下能争取的获取远程配置但是部署到linux上死活都没有内容&#xff0c;然后开始了远程调试&#xff0c;这里顺带讲解下获取配置文件如果使用的是Git源&#xff0c;config service是如何响应接口并返回配置信息的。先说问题&#xff0c;我的服务名原本是abc-abc-abc…

React 中 useEffect

React 中 useEffect 是副作用函数&#xff0c;副作用函数通常是处理外围系统交互的逻辑。那么 useEffect 是怎处理的呢&#xff1f;React 组件都是纯函数&#xff0c;需要将副作用的逻辑通过副作用函数抽离出去&#xff0c;也就是副作用函数是不影响函数组件的返回值的。例如&a…

stthjpv:一款针对JWT Payload的安全保护工具

关于stthjpv stthjpv是一款针对JWT Payload的安全保护工具&#xff0c;这款工具集多种技术和思想于一身&#xff0c;可以通过不断改变相关参数值来防止Payload被解码&#xff0c;以帮助广大研究人员更好地保护JWT Payload的安全性。 除此之外&#xff0c;该工具还能够确保JWT …

外贸业务员如何克服打电话恐惧?

更多外贸干货及开发客户的方法&#xff0c;尽在微信【千千外贸干货】 每个人都曾经历过从零开始的阶段。在我们决定要做外贸销售的那一刻起&#xff0c;便意识到沟通的重要性。许多朋友提到&#xff0c;通常通过邮件开发客户&#xff0c;或者在B2B平台上回复客户的询盘。但真的…

技术干货丨如何加速工业数字孪生应用落地?

什么是数字孪生&#xff1f; “孪生”概念最早可追溯至NASA的阿波罗项目&#xff0c;随着数字化技术的进步&#xff0c;“孪生”概念应用从物理孪生向数字孪生发展。即“数字孪生”是对资产、进程或系统的一种数字化表示&#xff0c;并通过信息交互、数据同步等方式实现物理实体…

云计算【第一阶段(23)】Linux系统安全及应用

一、账号安全控制 1.1、账号安全基本措施 1.1.1、系统账号清理 将非登录用户的shell设为/sbin/nologin锁定长期不使用的账号删除无用的账号 1.1.1.1、实验1 用于匹配以/sbin/nologin结尾的字符串&#xff0c;$ 表示行的末尾。 &#xff08;一般是程序用户改为nologin&…

【Matlab 六自由度机器人】机器人动力学之推导拉格朗日方程(附MATLAB机器人动力学拉格朗日方程推导代码)

【Matlab 六自由度机器人】机器人动力学概述 近期更新前言正文一、拉格朗日方程的推导1. 单自由度系统2. 单连杆机械臂系统3. 双连杆机械臂系统 二、MATLAB实例推导1. 机器人模型的建立2. 动力学代码 总结参考文献 近期更新 【汇总】 【Matlab 六自由度机器人】系列文章汇总 …

原码、反码、补码、移码的计算转换

文章目录 正数负数原码 & 反码反码 -> 补码原码 <-> 补码移码 <- Other 方法总结练习 正数 原码 和 反码 和 补码 都是一样的不会发生变化 因此&#xff0c;计算的时候先看第一位 符号位 &#xff0c;只要能发现是正数&#xff0c;三者都不变 移码 在补码基础…

DataV大屏组件库

DataV官方文档 DataV组件库基于Vue &#xff08;React版 (opens new window)&#xff09; &#xff0c;主要用于构建大屏&#xff08;全屏&#xff09;数据展示页面即数据可视化&#xff0c;具有多种类型组件可供使用&#xff1a; 源码下载

Web渗透-逻辑漏洞

一、概述 逻辑漏洞是指由于程序逻辑不严或逻辑太复杂&#xff0c;导致一些逻辑分支不能够正常处理或处理错误&#xff0c;一般出现任意密码修改&#xff08;没有旧密码验证&#xff09;,越权访问&#xff0c;密码找回&#xff0c;交易支付金额等。对常见的漏洞进行过统计&…

蒙特卡洛法求定积分方

对于连续函数密度函数&#xff0c;求某一个区间的概率时&#xff0c;理论上通过积分获取&#xff0c; 以求曲线围成的面积为例 当我们在[a,b]之间随机取一点x时&#xff0c;它对应的函数值就是f(x)。接下来我们就可以用f(x)*(b-a)来粗略估计曲线下方的面积&#xff0c;也就是我…

探索区块链:颠覆性技术的崛起

目录 一、引言 二、区块链技术概述 三、区块链应用场景 四、区块链面临的挑战 五、区块链的未来展望 六、结语 一、引言 在数字化浪潮的推动下&#xff0c;区块链技术以其独特的去中心化、透明性和不可篡改性等特性&#xff0c;正在逐步改变我们的生活。从金融领域到供应…

最新Node.js安装及配置详细教程

文章目录 下载Node.js安装Node.js配置Node.js1、修改npm包的全局安装路径和缓存路径2、环境变量设置3、镜像源配置4、安装其他包管理工具 下载Node.js 下载&#xff1a;https://nodejs.org/en/download/prebuilt-installer&#xff0c;下载LTS版本的&#xff0c;LTS(Long Time…

最小生成树拓展应用

文章目录 最小生成树拓展应用理论基础 题单1. [新的开始](https://www.acwing.com/problem/content/1148/)2. [北极通讯网络](https://www.acwing.com/problem/content/1147/)3. [走廊泼水节](https://www.acwing.com/problem/content/348/)4. [秘密的牛奶运输](https://www.ac…

001 SpringMVC介绍

文章目录 基础概念介绍BS和CS开发架构应用系统三层架构MVC设计模式 SpringMVC介绍SpringMVC是什么SpringMVC与Spring的联系为什么要学习SpringMVC 六大组件介绍六大组件(MVC组件其他三大组件)说明 基础概念介绍 BS和CS开发架构 一种是C/S架构&#xff0c;也就是客户端/服务器…

【雷丰阳-谷粒商城 】【分布式高级篇-微服务架构篇】【15】异步_线程池

持续学习&持续更新中… 守破离 【雷丰阳-谷粒商城 】【分布式高级篇-微服务架构篇】【15】异步_线程池 初始化线程的 4 种方式开发中为什么使用线程池线程池七大参数线程池工作原理常见的 4 种线程池生产中如何使用线程池&#xff1f;CompletableFuture 异步编排—简介业务…

dataX同步SQLserver到MySQL数据

引用datax官方描述&#xff1a; DataX 是阿里云 DataWorks数据集成 的开源版本&#xff0c;在阿里巴巴集团内被广泛使用的离线数据同步工具/平台。DataX 实现了包括 MySQL、Oracle、OceanBase、SqlServer、Postgre、HDFS、Hive、ADS、HBase、TableStore(OTS)、MaxCompute(ODPS…