前言

Spring Security是一个功能强大且高度且可定制的身份验证和访问控制框架,包含标准的身份认证和授权。

本文主要介绍SpringBoot中如何配置使用 Spring Security 安全认证框架并简述相关原理和步骤。

核心认证流程解析

在这里插入图片描述

  1. 请求过滤
  • 用户提交登录表单
  • AbstractAuthenticationProcessingFilter 过滤请求,创建 AbstractAuthenticationToken

以默认提供的 UsernamePasswordAuthenticationFilter举例:

public class UsernamePasswordAuthenticationFilter extendsAbstractAuthenticationProcessingFilter {public UsernamePasswordAuthenticationFilter() {// 设置过滤规则super(new AntPathRequestMatcher("/login", "POST"));}public Authentication attemptAuthentication(HttpServletRequest request,HttpServletResponse response) throws AuthenticationException {// ......String username = obtainUsername(request);String password = obtainPassword(request);if (username == null) {username = "";}if (password == null) {password = "";}username = username.trim();// 根据请求参数设置 UsernamePasswordAuthenticationToken 实例UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);setDetails(request, authRequest);return this.getAuthenticationManager().authenticate(authRequest);}// ......
}
  1. 认证管理器
  • AuthenticationManager(通常是 ProviderManager)协调认证过程,根据 AbstractAuthenticationToken类型 选择对应的 AuthenticationProvider

ProviderManager中根据不同的 Token 类型匹配不同的 Provider

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;boolean debug = logger.isDebugEnabled();// 遍历所有已注册的 providers ,匹配能处理当前 authentication 的 provider 进行认证处理for (AuthenticationProvider provider : getProviders()) {// 判断provider是否可以处理当前的authenticationif (!provider.supports(toTest)) {continue;}try {// 执行认证逻辑,返回认证结果result = provider.authenticate(authentication);if (result != null) {copyDetails(authentication, result);break;}} catch (AccountStatusException | InternalAuthenticationServiceException e) {prepareException(e, authentication);throw e;} catch (AuthenticationException e) {lastException = e;}}// .......throw lastException;
}
  • 匹配到对应的 provider 后,调用 provider.authenticate(authentication);执行实际的认证过程。

:::tips
认证过程以 AbstractUserDetailsAuthenticationProvider(实现DaoAuthenticationProvider)为例,大致过程为:

  • getUserDetailsService().loadUserByUsername(username); 加载用户信息
  • preAuthenticationChecks.check(user); 校验用户信息,是否锁定、过期、可用等
  • additionalAuthenticationChecks(user,(UsernamePasswordAuthenticationToken) authentication); 验证用户密码

:::

  1. 认证后处理
  • 认证成功:生成已认证的 Authentication 对象,存入 SecurityContext
  • 认证失败:抛出 AuthenticationExceptionAuthenticationEntryPoint 处理
组件职责典型实现类
AbstractAuthenticationProcessingFilter拦截认证请求,封装认证对象UsernamePasswordAuthenticationFilter
AuthenticationManager认证流程协调者ProviderManager
AuthenticationProvider执行具体认证逻辑DaoAuthenticationProvider
UserDetailsService加载用户数据自定义实现类

其中 UsernamePasswordAuthenticationFilterUsernamePasswordAuthenticationToken为框架自带的 登录请求过滤和Token实例。

如需自定义登录请求过滤和Token实例,可自行实现 AbstractAuthenticationProcessingFilterAbstractAuthenticationToken接口。

不同的 AbstractAuthenticationToken 通常有不同的 AuthenticationProvider与之对应,用于实现不同的认证逻辑。

自定义的认证逻辑中,通常都是对 AbstractAuthenticationTokenAuthenticationProvider 的不同实现。

JWT

JWT(JSON Web Token) 是一种轻量级的开放标准(RFC 7519),用于在网络应用间安全地传输信息。它通常用于 身份认证(Authentication) 和 数据交换(Information Exchange),特别适合 前后端分离 和 无状态(Stateless) 的应用场景。

JWT在登录中的应用过程

  1. 用户提交 用户名 + 密码 登录
  2. 服务器验证后,生成 JWT 并返回给客户端
  3. 客户端存储 JWT(通常放 localStorageCookie
  4. 后续请求 在 Authorization 头携带 JWT
  5. 服务器 验证 JWT 签名,并解析数据

特点

  • 防篡改:签名(Signature)确保 Token 未被修改
  • 可设置有效期(exp 字段)避免长期有效
  • 无状态:服务器不需要存储 Session,适合分布式系统

自定义认证逻辑


接下来根据 Spring Security 的认证过程和JWT的特点进行自定义登录逻辑的编写

核心类图

在这里插入图片描述

登录流程

在这里插入图片描述

具体实现

JwtLoginFilter

实现 AbstractAuthenticationProcessingFilter接口

public class JwtLoginFilter extends AbstractAuthenticationProcessingFilter {public JwtLoginFilter() {// 设置当前 Filter ,也就是需要过滤的登录URLsuper(new AntPathRequestMatcher("/auth/login", "POST"));}@Overridepublic Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)throws AuthenticationException, IOException, ServletException {// 获取前端传递登录模式String loginType = request.getParameter("loginType");Authentication authentication = null;// 判断前端使用的登录模式if (CommonConstant.LoginType.SMS.equals(loginType)) {// 手机短信String phone = request.getParameter("phone");String code = request.getParameter("code");authentication = new SmsAuthenticationToken(phone, code);}if (CommonConstant.LoginType.WX.equals(loginType)) {String code = request.getParameter("code");authentication = new WxAuthenticationToken(code);}if (authentication == null) {throw new UnsupportedLoginTypeException();}return getAuthenticationManager().authenticate(authentication);}
}

SmsAuthenticationToken

TIPS:如果需要多种认证模式,如:用户密码、短信认证、扫描登录、三方认证等,可实现不同的 Token实例,并实现与之对应的 Provider

以短信认证Token SmsAuthenticationToken举例

public class SmsAuthenticationToken extends AbstractAuthenticationToken {private final String phone;private final String code;public SmsAuthenticationToken(String phone, String code) {super(new ArrayList<>());this.phone = phone;this.code = code;}@Overridepublic String getCredentials() {return code;}@Overridepublic String getPrincipal() {return phone;}
}

SmsAuthProvider

具体实现短信认证的逻辑,主要工作原理是将前端传递的手机号和短信验证码进行匹配校验,如果合法,则认证成功,如果不合法,返回认证失败。

@Component
public class SmsAuthProvider implements AuthenticationProvider {@Autowiredprivate AbstractLogin abstractLogin;@Autowiredprivate JwtUtil jwtUtil;/*** 验证手机验证码登录认证** @param authentication the authentication request object.* @return* @throws AuthenticationException*/@Overridepublic Authentication authenticate(Authentication authentication) throws AuthenticationException {SmsAuthenticationToken token = (SmsAuthenticationToken) authentication;String phone = token.getPrincipal();String code = token.getCredentials();try {UserDetails userDetails = abstractLogin.smsLogin(phone, code);token.setDetails(userDetails);} catch (AuthenticationException authenticationException) {throw authenticationException;} catch (Exception e) {throw new LoginFailException();}return token;}@Overridepublic boolean supports(Class<?> authentication) {return SmsAuthenticationToken.class.equals(authentication);}
}

SpringBoot配置过程


我们已在上述的过程中将核心的认证逻辑实现,接下来就是把对应的代码配置到 Spring Security 工程之中。

JwtAuthConfig

JwtAuthConfig实现 WebSecurityConfigurerAdapter作为整体的配置入口

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true,securedEnabled = true)
public class JwtAuthConfig extends WebSecurityConfigurerAdapter {@Autowiredprivate JwtLoginConfig loginConfig;@Overridepublic void configure(WebSecurity web) throws Exception {super.configure(web);}@Overrideprotected void configure(HttpSecurity http) throws Exception {http.csrf().disable().formLogin().disable()// 应用登录相关配置信息.apply(loginConfig).and().authorizeRequests()// 放行登录 URL .antMatchers("/auth/login").permitAll();}
}

该配置类中,只做了初始化的简单配置,如设置放行登录URL、禁用 csrf、禁用 默认的formLogin等。更多的登录认证配置在 JwtLoginConfig中进行。

JwtLoginConfig

JwtLoginConfig实现了SecurityConfigurerAdapterSecurityConfigurerAdapter 是 Spring Security 的核心配置基类,用于自定义安全规则(如认证、授权、过滤器链等)。

配置信息如下:

@Configuration
public class JwtLoginConfig extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity> {@Autowiredprivate LoginSuccessHandler successHandler;@Autowiredprivate LoginFailHandler failHandler;@Autowiredprivate JwtProviderManager jwtProviderManager;/*** 将登录接口的过滤器配置到过滤器链中* 1. 配置登录成功、失败处理器* 2. 配置自定义的userDetailService(从数据库中获取用户数据)* 3. 将自定义的过滤器配置到spring security的过滤器链中,配置在UsernamePasswordAuthenticationFilter之前* @param http*/@Overridepublic void configure(HttpSecurity http) {JwtLoginFilter filter = new JwtLoginFilter();// authenticationManager 中已经预设系统内的 provider 集合filter.setAuthenticationManager(jwtProviderManager);//认证成功处理器filter.setAuthenticationSuccessHandler(successHandler);//认证失败处理器filter.setAuthenticationFailureHandler(failHandler);//将这个过滤器添加到UsernamePasswordAuthenticationFilter之后执行http.addFilterAfter(filter, UsernamePasswordAuthenticationFilter.class);}
}

JwtProviderManager

从上文中的认证过程(时序图)中,AuthenticationManager 是委托 ProviderManager进行认证模式的匹配和执行对应的 provider。

:::tips
为了后续的多认证模式的支持和动态匹配,所以将 ProviderManager 交给 Spring 容器管理,并且通过构造方法将平台内所有已经注册到Spring容器中的 provider进行注入,以达到自动装配的目的。

注:暂只做简单实现。

:::

@Component
public class JwtProviderManager extends ProviderManager {public JwtProviderManager(List<AuthenticationProvider> providers) {super(providers);}
}

LoginSuccessHandler

认证成功后,对认证结果生成JWT Token 返回前端

public class LoginSuccessHandler implements AuthenticationSuccessHandler {@Autowiredprivate JwtUtil jwtUtil;@Autowiredprivate NacosHcUserConfigProperties configProperties;@Overridepublic void onAuthenticationSuccess(HttpServletRequest request,HttpServletResponse response,Authentication authentication)throws IOException, ServletException {// 生成 token 返回前端
//        Object principal = authentication.getPrincipal();UserDetails details = (UserDetails) authentication.getDetails();// accessToken 过期时间 30分钟Long accessTokenExpireSeconds = configProperties.getAuth().getAccessTokenExpireSeconds();// refreshToken 过期时间 6小时Long refreshTokenExpireSeconds = configProperties.getAuth().getRefreshTokenExpireSeconds();String accessToken = jwtUtil.createToken(details.getUsername(), accessTokenExpireSeconds);String refreshToken = jwtUtil.createToken(accessToken, refreshTokenExpireSeconds);Map<String, String> tokenMap = new HashMap<>();tokenMap.put("accessToken", accessToken);tokenMap.put("refreshToken", refreshToken);response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);response.getWriter().write(JSON.toJSONString(ApiResult.success(tokenMap)));}
}

END

至此,相关 Spring Security 配置已完成!💯💯

🧑‍💻🧑‍💻🧑‍💻

下一篇继续探究 Spring Security 在登录后的认证鉴权过程。

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

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

华为云开发者空间 × DeepSeek-R1 智能融合测评:云端开发与AI客服的协同进化

前言&#xff1a; 华为开发者空间&#xff0c;是为全球开发者打造的专属开发者空间&#xff0c;致力于为每位开发者提供一台云主机、一套开发工具和云上存储空间&#xff0c;当普惠云资源遇见推理大模型&#xff0c;企业服务与开发效能的范式革命正在加速。华为云开发者空间&am…

二分查找----4.搜索旋转排序数组

题目链接 /** 升序数组在某个位置被分割为前后两部分,前后两部分整体互换;在被改变后的数组中找到目标值 O(log n)---> 二分查找 特点: 旋转后的数组被分割为两个独立的递增区间 左半区的最小值,大于右半区的最大值(mid所在区间的判断依据) 二分策略: 首先判断mid落在左区间…

地球表面附近两点之间距离、高低角和方位角的计算方法,VC++代码实操!

书接上文&#xff0c;这篇文章介绍具体的VC编程实现&#xff0c;代码实操。任何一个算法&#xff0c;你必须将其编写为代码&#xff0c;运行结果正确&#xff0c;才算真正掌握了&#xff0c;否则都是似懂非懂&#xff0c;一知半解&#xff0c;下面先给出仿真结果的截图&#xf…

uniapp各大平台导航组件

最近有个需求要点击导航然后跳出各家导航软件话不多出直接贴出代码&#xff1a;这个可以作为组件引入<template><view><view class"nav" :style"{color: customColor}" click.stop"openMap">{{title}}</view><!-- 弹…

Access开发一键删除Excel指定工作表

Hi&#xff0c;大家好&#xff01;又到了每周给大家更新的时间了&#xff0c;这周给大家讲讲excel的处理操作吧。在开始前&#xff0c;先给大家汇报一下我们框架的进度&#xff0c;最近两周没有直播&#xff0c;所以大家不太清楚目前的进度&#xff0c;框架目前就差权限了&…

无广告终端安全产品推荐:打造纯净办公环境的安全之选

在数字化办公时代&#xff0c;终端安全防护是企业和个人不可忽视的重要环节。然而&#xff0c;许多传统安全软件往往伴随着频繁的广告弹窗和推广信息&#xff0c;不仅干扰正常工作&#xff0c;还可能成为潜在的安全隐患。本文将为您介绍几款「无广告、无捆绑」的终端产品&#…

使用UE5自带节点InteriorCubemap制作假室内效果

Interior Mapping&#xff08;室内映射&#xff09;是一种用着色器方法模拟室内结构纹理的方式&#xff0c;避免了真实对室内场景建模造成的模型面数渲染开销&#xff0c;在《蜘蛛侠》《城市天际线》等游戏中都采用了该技术。 UE自带了节点InteriorCubemap&#xff08;Unity S…

基于单片机睡眠质量/睡眠枕头设计

传送门 &#x1f449;&#x1f449;&#x1f449;&#x1f449;其他作品题目速选一览表 &#x1f449;&#x1f449;&#x1f449;&#x1f449;其他作品题目功能速览 概述 随着现代社会生活节奏的加快&#xff0c;睡眠质量问题日益受到人们的关注。本研究设计了一种基于…

Ajax第一天

AJAX概念&#xff1a;AJAX 是浏览器与服务器进行数据通信的技术&#xff08;把数据变活&#xff09;语法&#xff1a;1.引入 axios.js&#xff1a;https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js2.使用 axios 函数✓ 传入配置对象✓ 再用 .then 回调函数接收结果&#…

AI大模型各类概念扫盲

以下内容整理自AI&#xff0c;进行一个概念扫盲&#xff1a;Prompt&#xff08;提示词&#xff09; Prompt是用户提供给AI模型的指令或问题&#xff0c;用于引导模型生成特定输出。良好的Prompt设计能显著提升模型的任务理解能力和响应质量&#xff0c;例如通过结构化提示&…

Linux系统编程——网络

一、TCP/UDP 1、osi模型 物理层、数据链路层、网络层、传输层、会话层、表示层、应用层&#xff08;下层为上层提供服务&#xff09; 2、TCP/IP模型&#xff08;TCP/IP协议栈&#xff09; 应用层&#xff1a; HTTP&#xff08;超文本传输协议&#xff09;、FTP&#xff08;文件…

taro+pinia+小程序存储配置持久化

主要通过taro的getStorageSync,setStorageSync实现配置持久化 // https://pinia.esm.dev/introduction.html import { defineStore } from pinia; import { CreditCardDateUtils } from /untils/compute; import { getStorageSync, setStorageSync } from "tarojs/taro&qu…

抖音小游戏好做吗?

从0到1&#xff0c;教你打造爆款抖音小游戏随着移动互联网的发展&#xff0c;抖音小游戏凭借便捷即玩、流量庞大等优势&#xff0c;成为游戏开发者的热门选择。想知道如何开发出一款吸睛又好玩的抖音小游戏吗&#xff1f;下面就为你详细介绍开发流程。一、前期规划明确游戏类型…

Spring Boot 3核心技术面试指南:从迁移升级到云原生实战,9轮技术攻防(含架构解析)

面试官&#xff1a;cc程序员&#xff0c;聊聊Spring Boot 3的那些事儿&#xff1f; 场景背景 互联网大厂云原生架构部面试官老王&#xff0c;与自称"Spring Boot骨灰粉"的cc程序员展开技术对决。 面试过程 第一轮&#xff1a;迁移升级 面试官&#xff1a;Spring Boot…

技术演进中的开发沉思-42 MFC系列:Components 与 ActiveX Controls

点击程序启动时&#xff0c;是不是看过有加载的画面。在VC开发时&#xff0c;可使用 VC 的 Component Gallery&#xff0c;找到 Splash screen 组件&#xff0c;当时觉得组件就是给程序员的暖手宝。一、Component GalleryComponent Gallery 在 VC 里的位置很特别 —— 它藏在 “…

抽象类、接口、枚举

第八天&#xff08;坚持&#xff09;抽象类1.什么是抽象类&#xff0c;作用特点。抽象类是面向对象编程中一种特殊的类&#xff0c;它不能被实例化&#xff0c;主要用于作为其他类的基类&#xff08;父类&#xff09;。抽象类的主要作用是定义公共结构和行为规范&#xff0c;同…

在Ubuntu上使用QEMU仿真运行ARM汇编

ARM汇编一般无法在PC上直接运行&#xff0c;因为ARM和x86架构是不一样的。但是很多时候用ARM开发板是很不方便的&#xff0c;所以能不能直接在PC上仿真运行ARM汇编来练习呢&#xff1f;当然可以&#xff0c;那就是&#xff1a;使用QEMU来仿真。这篇文章我们就来演示下如何在Ubu…

【趣味解读】淘宝登录的前后端交互机制:Cookie-Session 如何保障你的账户安全?

在现代Web应用中&#xff0c;前后端交互是核心功能之一&#xff0c;而用户认证又是其中最关键的部分。本文将以淘宝登录为例&#xff0c;详细解析基于Cookie-Session的前后端交互流程&#xff0c;帮助开发者理解这一常见的安全认证机制。生动理解一下什么是cookie和seesion我们…

贪心算法(基础算法)

1.引言 ok啊&#xff0c;拖更这么长时间也是没有压力&#xff08;doge&#xff09; 不说啥&#xff0c;直接进入正题。 2.概念 这个贪心算法呢&#xff0c;看名字就知道&#xff0c;不就是每个步骤都挑最好的嘛&#xff0c;有啥难的。 这么说的话......其实确实&#xff0c…

简单的mcp 服务示例

参考&#xff1a;https://www.bilibili.com/video/BV1nyVDzaE1x 编写自己的tools.py #### tools.py from pathlib import Path import osbase_dir Path("./test")def read_file(name: str) -> str:"""Return file content. If not exist, return …