Spring Security是如何实现自定义认证的

Spring Security (一):自定义认证 Spring Security 是一个提供身份验证授权和针对常见攻击的保护的框架,spring security 在程序启动时,向spring中注入一个默认的filterChian,按照顺序,依次执行filter,对用户信息进行认证,授权。官网链接: Spring Security :: Spring SecurityCorsFilterCsrfFilterOpenIDSiteMinder其中,默认的认证过滤器为 UsernamePasswordAuthenticationFilter。 阅读详情

Spring Security 允许通过自定义认证机制来处理各种身份验证场景。下面是一个简单的示例:

1. 定义自定义认证的流程

在Spring Security中,认证流程通常涉及以下组件:

  • Authentication 对象: 代表用户的认证请求和结果。
  • AuthenticationManager 接口: 认证请求的主要入口,负责委派给合适的 AuthenticationProvider。
  • AuthenticationProvider 接口: 实际执行身份验证逻辑的组件。 它可以针对特定类型的认证请求 (如用户名/密码、OAuth 2.0 等) 提供验证。
  • UserDetailsService 接口: (可选) 用于从数据源 (如数据库) 加载用户信息。 通常用于用户名/密码认证。
  • UserDetails 接口: 代表加载的用户信息,包含用户名、密码、权限等。

2. 实现自定义 Authentication 对象

定义两个 Authentication 对象:一个用于认证 请求,一个用于认证 成功后 的结果。

// 认证请求对象
public class CustomAuthenticationToken implements Authentication {

    private final Object principal; // 用户名/标识
    private Object credentials; // 密码/凭据
    private Collection<? extends GrantedAuthority> authorities; // 权限
    private boolean authenticated; // 认证状态

    public CustomAuthenticationToken(Object principal, Object credentials) {
        this.principal = principal;
        this.credentials = credentials;
        this.authenticated = false; // 初始状态:未认证
    }

    public CustomAuthenticationToken(Object principal, Object credentials, Collection<? extends GrantedAuthority> authorities) {
        this.principal = principal;
        this.credentials = credentials;
        this.authorities = authorities;
        this.authenticated = true; // 认证成功,设置已认证
    }



    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return authorities;
    }

    @Override
    public Object getCredentials() {
        return credentials;
    }

    @Override
    public Object getDetails() {
        return null; // 可选,用于存放附加信息
    }

    @Override
    public Object getPrincipal() {
        return principal;
    }

    @Override
    public boolean isAuthenticated() {
        return authenticated;
    }

    @Override
    public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {
        this.authenticated = isAuthenticated;
    }

    @Override
    public String getName() {
        return principal != null ? principal.toString() : null;
    }

    @Override
    public String toString() {
        return "CustomAuthenticationToken{" +
                "principal=" + principal +
                ", authenticated=" + authenticated +
                ", authorities=" + authorities +
                '}';
    }
}

3. 实现自定义 AuthenticationProvider

这是认证逻辑的核心。

import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;

@Component
public class CustomAuthenticationProvider implements AuthenticationProvider {

    // 模拟用户数据
    private static final String VALID_USERNAME = "testUser";
    private static final String VALID_PASSWORD = "password";

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        System.out.println("CustomAuthenticationProvider.authenticate() called");

        String username = (String) authentication.getPrincipal();
        String password = (String) authentication.getCredentials();

        System.out.println("Attempting authentication for user: " + username);

        if (VALID_USERNAME.equals(username) && VALID_PASSWORD.equals(password)) {
            System.out.println("Authentication successful for user: " + username);
            List<GrantedAuthority> authorities = new ArrayList<>();
            authorities.add(new SimpleGrantedAuthority("ROLE_USER")); // 添加用户角色

            // 创建认证成功后的 Authentication 对象
            CustomAuthenticationToken authenticationResult = new CustomAuthenticationToken(username, password, authorities);
            System.out.println("Authentication Result: " + authenticationResult);
            return authenticationResult;

        } else {
            System.out.println("Authentication failed for user: " + username);
            throw new AuthenticationServiceException("Invalid username or password");
        }
    }

    @Override
    public boolean supports(Class<?> authentication) {
        // 声明此 Provider 支持哪种 Authentication 类型
        return CustomAuthenticationToken.class.isAssignableFrom(authentication);
    }
}

要点:

  • authenticate() 方法: 接收 Authentication 请求对象,执行身份验证逻辑。 如果验证成功,返回一个 已认证 的 Authentication 对象 (通常包含用户权限)。 如果验证失败,抛出一个 AuthenticationException。
  • supports() 方法: 指示此 AuthenticationProvider 是否支持给定的 Authentication 类型。 必须实现。
  • 异常处理:在身份验证失败时,抛出适当的 AuthenticationException 子类。
  • 打印日志:在身份验证的不同阶段打印日志,以便调试和跟踪。

4. 配置 Spring Security

使用 Spring Security 配置类来启用自定义认证。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Autowired
    private CustomAuthenticationProvider customAuthenticationProvider;

    @Bean
    public AuthenticationManager authenticationManager(HttpSecurity http) throws Exception {
        AuthenticationManagerBuilder authenticationManagerBuilder = http.getSharedObject(AuthenticationManagerBuilder.class);
        authenticationManagerBuilder.authenticationProvider(customAuthenticationProvider);
        return authenticationManagerBuilder.build();
    }


    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                .antMatchers("/public/**").permitAll() // 允许访问公共资源
                .anyRequest().authenticated() // 其他所有请求需要认证
                .and()
                .formLogin() // 使用表单登录
                .permitAll()
                .and()
                .logout()
                .permitAll();

        return http.build();
    }

}

关键配置:

  • @EnableWebSecurity: 启用 Spring Security。
  • AuthenticationManagerBuilder: 用于配置 AuthenticationManager。 在这里,将自定义 AuthenticationProvider 添加到构建器中。

5. 创建一个简单的Controller测试

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {

    @GetMapping("/public/hello")
    public String helloPublic() {
        return "Hello, Public!";
    }

    @GetMapping("/hello")
    public String helloAuthenticated() {
        return "Hello, Authenticated User!";
    }
}

6. 测试

  1. 启动你的 Spring Boot 应用程序。
  2. 访问 /public/hello。 应该可以直接访问,因为配置允许匿名访问。
  3. 访问 /hello。 你会被重定向到登录页面。
  4. 使用用户名 testUser 和密码 password 登录。
  5. 如果登录成功,你应该能够看到 “Hello, Authenticated User!”。

控制台输出示例

当尝试登录时,你会在控制台中看到类似以下的输出:

CustomAuthenticationProvider.authenticate() called
Attempting authentication for user: testUser
Authentication successful for user: testUser
Authentication Result: CustomAuthenticationToken{principal=testUser, authenticated=true, authorities=[ROLE_USER]}

调试技巧

  • 断点: 在 authenticate() 方法中设置断点,逐步调试认证流程。

  • 日志级别: 调整 Spring Security 的日志级别 (例如,设置为 DEBUG),以获取更详细的输出。 可以在 application.properties 或 application.yml 中设置:

    logging.level.org.springframework.security=DEBUG
    
  • HTTP Tracing: 使用浏览器开发者工具或 HTTP 客户端 (如 Postman) 查看 HTTP 请求和响应,以诊断认证问题。

扩展

  • 密码编码: 强烈建议使用 PasswordEncoder 对密码进行编码,而不是直接存储明文密码。 Spring Security 提供了多种 PasswordEncoder 实现 (如 BCryptPasswordEncoder)。
  • UserDetailsService: 使用 UserDetailsService 从数据库或其他数据源加载用户信息。
  • OAuth 2.0 和 JWT: 如果需要更高级的认证机制,可以集成 OAuth 2.0 或 JWT (JSON Web Token)。
  • 自定义异常处理: 创建自定义的 AuthenticationException 子类,以便更精确地处理不同类型的认证错误。
  • 权限模型: 设计灵活的权限模型,以便控制用户对资源的访问。
SpringBoot Security 自定义用户认证 下面将实现Spring boot整合Spring Security 实现自定义内存身份认证的实现。 阅读详情

相关推荐

Spring Security自定义认证逻辑实现图片验证码登录

相信大家在网上冲浪都遇到过登录时输入图片验证码的情况,既然我们已经学习了 Spring Security,也上手实现过几个案例,那不妨来研究一下如何实现这一功能。首先需要明确的是,登录时输入图片验证码,属于认证功能的一部分,所以本文不涉及授权功能。我们复用之前的项目 springboot-security-inmemory,通过 postman 进行测试,不需要额外构建 html 页面。

BASK2312的博客 978

SpringSecurity自定义认证

​ 学习了SpringSecurity的使用,以及跟着源码分析了一遍认证流程,掌握了这个登录认证流程,才能更方便我们做自定义操作。​ 下面我们来学习下怎么实现多种登录方式,比如新增加一种邮箱验证码登录的形式,但SpringSecurity默认的Usernamepassword方式不影响。自定义一个邮箱验证码的认证,将邮箱号码作为key,验证码作为value存放到Redis中缓存。首先回顾下之前源码分析的认证流程,如下图:首先前端是填写邮箱,点击获取验证码输入获取到的验证码,点击登录按钮,发送登录接口(/em

张氏小毛驴的博客 5292

六、Spring Security认证和授权-实现自定义短信验证码登陆功能

一、图片验证码验证流程回顾 上期已经实现了图片验证码的功能,我们来回顾一下大概流程: 1、 客户端生成一个唯一标识,然后发起图片验证码请求,请求路径中携带这个唯一标识,例如:http://localhost:8066/auth/code/image/039988e0-1994-11eb-8a54-abdddf75aa45 2、 服务端接收到获取验证码请求,读取请求路径中的唯一标识(例如:039988e0-1994-11eb-8a54-abdddf75aa45);生成4位随机数作为验证码,合成验证码图片(创建

STIll_ly的博客 1348

Spring Security自定义用户认证

Spring Security自定义用户认证 在Spring Boot中开启Spring Security一节中我们简单地搭建了一个Spring Boot + Spring Security的项目,其中登录页、用户名和密码都是由Spring Security自动生成的。Spring Security支持我们自定义认证的过程,如使用自定义的登录页替换默认的登录页,用户信息的获取逻辑、登录成功或失败后的处理逻辑等。这里将在上一节的源码基础上进行改造。 配置自定义登录页 为了方便起见,我们直接在src/main/

艾华生的博客 4574

Springboot +spring security,自定义认证器实现验证码功能

Springboot +spring security,自定义认证器实现验证码功能

weixin_40991408的博客 1083

spring Cloud微服务 security+oauth2认证授权中心自定义令牌增强,并实现登录和退出_spring security实现微服务用户中心

*** 登录认证对象*/@Getter@Setter* 配置授权以及令牌的访问端点和令牌服务*/@Override// 认证器// 具体登录的方法// token 存储的方式:Redis// 令牌增强对象,增强返回的结果// 获取登录用户的信息,然后设置});

2401_87555332的博客 1090

spring security 自定义Provider 实现多种认证方式

我的系统里有两种用户,对应数据库两张表,所以必须自定义provider 和 AuthenticationToken,这样才能走到匹配自定义的UserDetailsService,我这里只粘贴一套代码,另一套同理复制就行。 必须自定义原因在于,自定义prodvider会根据重写的support方法判断是否匹配自定义AuthenticationToken,匹配后可以调用自定义的UserDetailsService的方法loadUserByUsername(String username),这样就直接查对应的数

yfx000的专栏 1万+

Doris + Iceberg 实现高效数据湖分层:架构解析与最佳实践

本文深入解析了如何利用Doris与Iceberg构建高效的数据湖冷热分层架构。通过将高频访问的热数据存储在Doris中以实现毫秒级查询,同时将历史冷数据归档至低成本的Iceberg存储,该方案在保障查询性能的同时显著降低了总体拥有成本。文章详细阐述了从架构设计、自动化迁移到统一查询的最佳实践,为应对海量数据下的成本与性能平衡提供了实战指南。

weixin_29207533的博客 135

【Spring Security系列】Spring Security使用自定义认证实现图形验证码

前面使用过滤器的方式实现了带图形验证码的验证功能,属于Servlet层面,简单、易理解。其实,Spring Security还提供了一种更优雅的实现图形验证码的方式,即自定义认证。 1.认识AuthenticationProvider 在学习Spring Security的自定义认证之前,有必要了解Spring Security是如何灵活集成多种认证技术的。 我们所面对的系统中的用户,在Spring Security中被称为主体(principal)。主体包含了所有能够经过验证而获得系统访问权限的

qq_28248897的博客 639

翁恺-C语言程序设计 PTA习题集

代码练习题

qq_46085472的博客 7644

Modbus CRC和LRC算法研究及代码实现

一、CRC(循环冗余校验) 1 CRC16实现流程 XOR = 异或 N = 字节的信息位 POLY = CRC16 多项式计算 = 1010 0000 0000 0001 (生成多项式 = 1 + x2 + x15 + x16) 在CRC16中,发送的第一个字节位低字节 2 CRC16实例推导 3 CRC16代码实现 unsigned short CRC16(unsigned char *a...

Hi, Boy 2892

Spring Security用户认证成功失败自定义实现

【一】Spring boot Security OAuth2用户登录失败事件发布及监听 【二】Spring Security用户认证成功失败源码分析 上一篇文章讲解了用户认证成功或者失败事件发布的整个流程, 这一篇就讲解下自定义的实现方式。首先看一下认证的异常都有哪些: 在org.springframework.security.authentication.event包下定义了发生认证时的所有事...

OceanSky的专栏 6755

【ROS】ROS局域网下多机通讯方法

最近工作中需要用到多机通讯,这里稍微总结一下使用方法。一、网络配置ifconfig这里举个例子,主机的IP地址为192.168.1.127,从机的IP地址为192.168.1.126;之后可测试一下能否互相ping通,成功后进行下一步。

weixin_43326110的博客 3360

Spring Security 实战:手把手实现 Email + Password 自定义认证

本文详细介绍了如何在Spring Security中实现自定义的"邮箱+密码"认证流程。文章从项目结构入手,分步讲解了核心实现:1)自定义EmailPasswordAuthenticationToken承载认证信息;2)创建EmailPasswordAuthenticationProvider处理认证逻辑;3)开发EmailPasswordAuthenticationFilter解析请求。通过将这些组件整合到Spring Security配置中,实现了完整的认证流程。项目基于JDK17和

weixin_38321813的博客 1864

Keil uVision5 STM32 startup_stm32f10x_md_vl.s error A3906U Malformed via file target not created..

🏆 本文收录于《全栈Bug调优(实战版)》专栏,致力于分享我在项目实战过程中遇到的各类Bug及其原因,并提供切实有效的解决方案。无论你是初学者还是经验丰富的开发者,本文将为你指引出一条更高效的Bug修复之路,助你早日登顶,迈向财富自由的梦想🚀!同时,欢迎大家关注、收藏、订阅本专栏,更多精彩内容正在持续更新中。让我们一起进步,Up!Up!Up!    备注: 部分问题/难题源自互联网,经过精心筛选和整理,结合数位十多年大厂实战经验资深大佬经验总结所得,数条可行方案供所需之人参考。

**My Coding Family** 2778

Python爬虫实战:利用最新技术爬取微信公众号文章(基于搜狗搜索)

使用最新Python版本确保兼容性和性能:比传统Requests更强大的HTML解析库Playwright:新一代浏览器自动化工具,比Selenium更高效Asyncio:异步IO框架提升爬虫效率Redis:分布式任务队列和去重MongoDB:非关系型数据库存储结构化数据本文详细介绍了如何利用Python最新技术栈构建一个功能强大的微信公众号文章爬虫。通过结合Playwright浏览器自动化、异步IO、分布式任务队列等技术,我们实现了一个能够绕过反爬机制、高效稳定抓取数据的解决方案。

2201_76125261的博客 1796

Spring Security 自定义拦截器Filter实现登录认证

Spring Security 自定义拦截器Filter 实现登录认证

qq_34898847的博客 7640

YOLO系列算法改进 | Neck改进篇 | 融合FAAFusion傅里叶角度对齐模块 | 攻克多尺度方向特征冲突,角度检测精度飙升! | CVPR 2026

YOLO系列算法改进 | Neck改进篇 | 融合FAAFusion傅里叶角度对齐模块 | 攻克多尺度方向特征冲突,角度检测精度飙升! | CVPR 2026 (以YOLO26最新目标检测模型为基础,利用FAAFusion傅里叶角度对齐模块改进Neck部分)

2502_91881744的博客 316

Spring Security + Jwt实现 自定义认证+自定义鉴权配置

Spring Security快速搭建自定义认证+鉴权配置

weixin_46275928的博客 1115

【Python爬虫(1)】专栏开篇:夯实Python基础

要想熟练掌握 Python 爬虫技术,扎实的 Python 基础是必不可少的。这就好比建造高楼大厦,Python 基础就是那稳固的基石。只有打好了这个基础,我们才能在爬虫的学习道路上稳步前行,理解并运用各种爬虫技术和框架。

邓邓子的博客 2026

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

Spring Security OAuth自定义认证:实现企业级需求

Spring Security OAuth自定义认证是现代企业应用开发中的关键技术,它让开发者能够灵活扩展OAuth 2.0协议来满足特定的业务需求。通过自定义认证机制,企业可以实现更严格的访问控制、集成内部身份验证系统,以及构建符合安全标准的API网关。 ## 为什么需要自定义认证? 在标准的OAuth 2.0流程中,客户端通过授权码、密码、客户端凭证等标准模式获取访问令牌。然而,在实际企业

gitblog_00498的博客 613

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

Spring Security用户认证和权限控制(自定义实现)

Spring Security用户认证和权限控制(自定义实现)1 说明2 用户认证相关的自定义实现2.1 自定义用户认证页面2.2 自定义退出功能2.3 自定义用户认证拦截器2.4 自定义用户认证处理器2.5 自定义用户认证对象2.6 自定义用户认证成功处理器2.7 自定义用户认证失败处理器2.8 自定义用户认证处理逻辑的应用3 权限控制相关的自定义实现3.1 自定义权限数据获取类3.2 自定义权...

Java大数据联盟 2万+

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

基于数据库自定义UserDetailsService实现Spring security认证

Spring security——基于数据库自定义UserDetailsService实现认证 本文将展示如何在spring security中创建基于数据库自定义UserDetailsService的认证服务。 UserDetailsService UserDetailsService接口用于返回用户相关数据。它有loadUserByUsername()方法,根据username查询用...

neweastsun的专栏 4万+

自定义【Spring Security】实现多种认证方式

自定义【Spring Security】实现多种认证方式

乐哥说的专栏 1767

spring security——学习笔记(day05)-实现自定义 AuthenticationProvider身份认证-手机号码认证登录

实现SpringSecurity自定义认证Provider 的代码,编写一个根据手机号码认证登录的实例

键上艺术家 8053

Spring Security(自定义注解和基于aop的注解鉴权实现的登录认证权限)

关于登录认证的权限编写流程,首先自定义需要使用的注解@RequiresPermissions ,@RequiresRoles,然后使用Spring AOP实现来进行注解鉴权,最后在注解鉴权的过程中获取登录用户的缓存信息的token来进行判断用户是否登录。如果判断用户登录成功后进行权限的认证,同样的在其过程中通过获取登录用户的权限列表与注解元数据进行对比是否存在权限。@Aspect@Component//定义AOP签名@Pointcut("@annotation("注解文件路径")")//注解鉴权。

weixin_52952621的博客 647
上一篇: Redis 的 Bitmap(位图)的使用场景
下一篇: MyBatis中是如何对占位符进行赋值的?
冰糖心书房
博客等级 码龄15年 6017粉丝 690原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

冰糖心书房

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值