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

一、基本源码解析

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();
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

数据在内存中的存储方式

&#x1f31f;&#x1f31f;作者主页&#xff1a;ephemerals__ &#x1f31f;&#x1f31f;所属专栏&#xff1a;C语言 目录 前言 一、整数的存储 二、大小端字节序及其判断 1.什么是大小端 2.为什么有大小端 3.用c语言编写程序判断大小端 三、浮点数的存储 1.浮点数…

第7章:Electron文件系统操作(2)

7.2 文件对话框 Electron 提供了 dialog 模块用于显示文件打开和保存对话框。 7.2.1 显示文件打开对话框 主进程代码&#xff1a; const { app, BrowserWindow, ipcMain, dialog } require(electron); const path require(path);let mainWindow;const createMainWindow …

【Unity学习笔记】A*寻路算法

文章目录 图寻路算法BFS广度优先算法DFS深度优先贪心算法 引入权重Dijkstra算法 A*算法C#实现步骤 Unity中的A*算法A*优化建议 图 图的知识盘点 pathfinding 作为一名计算机专业的学生&#xff0c;对于图这种数据结构也是烂熟于心了。图是一种包含了多个结点的数据结构&…

巴图自动化Modbus协议转Profinet协议网关模块连智能仪表与PLC通讯

一、现场要求:PLC作为控制器&#xff0c;仪表设备作为执行设备。执行设备可以实时响应PLC传送的指令&#xff0c;并将数据反馈给PLC&#xff0c;从而实现PLC对仪表设备的控制和监控&#xff0c;实现对生产过程的精确控制。 二、解决方案:通过巴图自动化Modbus协议转Profinet协议…

大模型面试题目

1.为什么需要做位置编码 位置编码&#xff08;Positional Encoding&#xff09;在变换器&#xff08;Transformer&#xff09;模型中非常重要&#xff0c;因为变换器架构本身没有内置的顺序信息。变换器使用的是自注意力机制&#xff0c;它能够捕捉输入序列中所有词之间的相关性…

Vscode 保存代码,代码自动格式化

我这里使用的插件是Prettier-Code formatter&#xff1a;自动缩进整理代码的格式&#xff0c;使用方法如下&#xff1a; 先在vscode商店找到插件并安装&#xff1a;安装插件之后&#xff0c;随便找到一个项目文件&#xff0c;右键选择格式化文档&#xff1a;选中我们安装的插件…

LVS-负载均衡

目录 一、概念 二、LVS工作原理 1. ipvs/ipvsadm 2.名词&#xff1a; 三、常用命令 四、工作模式 1.NAT地址转换模式 &#xff08;1&#xff09;工作流程 &#xff08;2&#xff09;特点 &#xff08;3&#xff09;实验过程 a.环境准备&#xff1a; b.修改测试机的…

Wing FTP Server

文章目录 1.Wing FTP Server简介1.1主要特点1.2使用教程 2.高级用法2.1Lua脚本,案例1 1.Wing FTP Server简介 Wing FTP Server&#xff0c;是一个专业的跨平台FTP服务器端&#xff0c;它拥有不错的速度、可靠性和一个友好的配置界面。它除了能提供FTP的基本服务功能以外&#…

android应用的持续构建CI(一)-- 总体设计

一、背景 接下里我希望通过一系列的文章&#xff0c;把android应用的构建梳理一遍&#xff0c;从总体设计到逐个环节的实现。 总体设计jenkins集成手动签名依赖环境应用管理 二、构建流程图 三、技术组件 jenkinsjdkgradle360加固 既然是android应用的持续构建&#xff0c…

科普文:Linux服务器性能调优之CPU调度策略和可调参数

概叙 进程 进程是操作系统虚拟出来的概念&#xff0c;用来组织计算机中的任务。计算机的核心是CPU&#xff0c;它承担了所有的计算任务&#xff1b;而操作系统是计算机的管理者&#xff0c;它负责任务的调度、资源的分配和管理&#xff0c;统领整个计算机硬件&#xff1b;应用…

5百多本分章节古籍内容大全ACCESS\EXCEL数据库

很多明清小说现在越来越不容易查看其内容&#xff0c;虽然之前搞到过一份《3万8千多古代文学大全ACCESS数据库》&#xff0c;但简体中文总让我感觉有删减、非原版的印象&#xff0c;今天正好遇到一个好的古籍网站&#xff0c;繁体字繁体文&#xff0c;感觉非常不错&#xff0c;…

微信小程序遮罩层显示

效果展示&#xff1a; wxml页面&#xff1a; <view classmodal-mask wx:if{{showModal}}><view class"modal-container"><view classmodal-content></view><view classmodal-footer bindtap"closeImage">//这个/images/ind…

电脑录音怎么录?简单四个方法轻松搞定!

在电脑上录制音频是一项非常实用的技能&#xff0c;适合多种场合的需求。例如&#xff0c;你可能需要录制自己的声音&#xff0c;用于录音广播、演示或视频制作&#xff1b;也可能需要录制电脑中的声音&#xff0c;如音乐、游戏音效或在线直播&#xff1b;或者需要捕捉浏览器中…

快排的实现

引言 作为c语言库函数的一种&#xff0c;快排在排序中的地位毋庸置疑. 而更加具体的实现如图&#xff1a; 快排的实现&#xff08;递归实现&#xff09; 原理 单趟:先假定第一个数设为key,如果左边指针的值比key大&#xff0c;且右边指针的值比key小&#xff0c;则将其交换.…

亚马逊云服务器的价格真的那么贵吗?一年要花多少钱?

亚马逊Web服务&#xff08;AWS&#xff09;作为全球领先的云计算平台&#xff0c;其定价策略常常引起用户的关注。很多人可能会问&#xff1a;"AWS真的那么贵吗&#xff1f;"实际上&#xff0c;这个问题的答案并不是简单的"是"或"否"&#xff0c…

JavaScript技术的小饰品销售管理系统-计算机毕业设计源码21597

摘 要 在当今的数字化时代&#xff0c;电子商务已经成为了商业领域中不可或缺的一部分。随着消费者对于购物体验的要求越来越高&#xff0c;一个高效、便捷、用户友好的小饰品销售管理系统显得尤为重要。 本系统旨在利用 JavaScript 技术&#xff0c;设计并实现一个功能强大的小…

黑马点评DAY5|商户查询缓存

商户查询缓存 缓存的定义 缓存就是数据交换的缓冲区&#xff08;Cache&#xff09;&#xff0c;是存储数据的临时地方&#xff0c;一般读写性能较高。 比如计算机的CPU计算速度非常快&#xff0c;但是需要先从内存中读取数据再放入CPU的寄存器中进行运算&#xff0c;这样会限…

ForkJoin框架与工作窃取算法详解

文章目录 一、ForkJoin框架概述1_核心概念2_主要类和方法1_ForkJoinPool2_ForkJoinTask 二、启用异步模式与否的区别三、ForkJoinPool的三种任务提交方式四、执行逻辑及使用示例1_示例&#xff1a;并行计算数组元素和2_forkJoinPool.submit3_ForkJoinTask<?>中任务的执行…

软件研发标准化流程文件

为了规范化系统开发流程&#xff0c;我们精心制定了一套详尽的规范文档。该文档旨在通过标准化、系统化的方法来显著提升开发效率与项目质量。流程始于明确需求阶段&#xff0c;通过深入细致的设计规划来确保解决方案既可行又具有前瞻性。随后&#xff0c;我们进入高效的编码实…

ClickHouse概述

ClickHouse概述 文章目录 ClickHouse概述ClickHouse是什么ClickHouse快的理由什么是OLAPClickHouse的特点列式存储DBMS 的功能多样化引擎高吞吐写入能力数据分区与线程级并行 ClickHouse的应用合适场景不适合场景 ClickHouse是什么 ClickHouse 是俄罗斯的 Yandex 于 2016 年开…