SpringSecurity认证的执行流程【完整流程图在文章结尾】

扩展篇:再探Spring Security过滤器链之SecurityContext 扩展篇:再探Spring Security过滤器链 在 概述(一):SpringSecurity的前世今生 中我们曾提过Spring Security底层是通过一组过滤器链来实现的,当时简单的介绍了几个比较重要的过滤器;并且在后面的几篇认证文章中都有比较详细的讲解。 但前几篇的系列文章更多的是关注 认证本身,对一些细枝末节没有额外的展开;而本篇文章的目的是再探 Spring Security 的过滤器链,完整的剖析全链路。 经过 认证(一):基于表单登录的认证模式 的介绍,我们对认证的流程有了一个比较全面的 阅读详情

SpringSecurity认证的执行流程

在Spring Security 中,与认证、授权相关的校验其实都是利用一系列的过滤器来完成的,这些过滤器共同组成了一个过滤器链,如下图所示:
在这里插入图片描述

当开启SpringSecurity的debug模式时,可以看到控制台打印出来的各个过滤器执行的顺序:

@EnableWebSecurity(debug=true)
public class SecurityConfig extends WebSecurityConfigurerAdapter
1、 WebAsyncManagerIntegrationFilter;
2、 SecurityContextPersistenceFilter;
3、 HeaderWriterFilter;
4、 CsrfFilter;
5、 LogoutFilter;
6、 UsernamePasswordAuthenticationFilter;
7、 DefaultLoginPageGeneratingFilter;
8、 DefaultLogoutPageGeneratingFilter;
9、 RequestCacheAwareFilter;
10、 SecurityContextHolderAwareRequestFilter;
11、 AnonymousAuthenticationFilter:如果之前的认证机制都没有更新SecurityContextHolder拥有的Authentication,那么一个AnonymousAuthenticationToken将会设给SecurityContextHolder;
12、 SessionManagementFilter;
13、 ExceptionTranslationFilter:用于处理在FilterChain范围内抛出的AccessDeniedException和AuthenticationException,并把它们转换为对应的Http错误码返回或者跳转到对应的页面;
14、 FilterSecurityInterceptor:负责保护WebURI,并且在访问被拒绝时抛出异常;

在上面图中所展示的一系列的过滤器中,和认证授权直接相关的过滤器是 AbstractAuthenticationProcessingFilter 和 UsernamePasswordAuthenticationFilter

但是你可能又会问,怎么没看到 AbstractAuthenticationProcessingFilter 这个过滤器呢?这是因为它是一个抽象的父类,其内部定义了认证处理的过程,UsernamePasswordAuthenticationFilter 就继承自 AbstractAuthenticationProcessingFilter

接下来详细介绍下这两个过滤器

AbstractAuthenticationProcessingFilter

在AbstractAuthenticationProcessingFilter 中定义了认证处理过程,具体如下:
在这里插入图片描述

由上图可知,在执行过滤器的时候会对请求进行校验requiresAuthentication(),如果校验通过后才会执行具体的认证逻辑。那这里校验的什么?这里先不继续说,后续会再次介绍。

当校验通过后,则会执行具体具体的认证逻辑attemptAuthentication,该方法是个抽象方法,具体的实现逻辑都是在子类中实现的,也就是UsernamePasswordAuthenticationFilter.

UsernamePasswordAuthenticationFilter

UsernamePasswordAuthenticationFilter是AbstractAuthenticationProcessingFilter的一个子类,认证与授权的相关校验均在此类中定义的。具体实现如下:

public class UsernamePasswordAuthenticationFilter extends
        AbstractAuthenticationProcessingFilter {

    public static final String SPRING_SECURITY_FORM_USERNAME_KEY = "username";
    public static final String SPRING_SECURITY_FORM_PASSWORD_KEY = "password";

	// ……

    // ~ Constructors
    // ===================================================================================================

    public UsernamePasswordAuthenticationFilter() {
        super(new AntPathRequestMatcher("/login", "POST"));
    }

    public Authentication attemptAuthentication(HttpServletRequest request,
                                                HttpServletResponse response) throws AuthenticationException {
        if (postOnly && !request.getMethod().equals("POST")) {
            throw new AuthenticationServiceException(
                    "Authentication method not supported: " + request.getMethod());
        }

        String username = obtainUsername(request);
        String password = obtainPassword(request);

        if (username == null) {
            username = "";
        }

        if (password == null) {
            password = "";
        }

        username = username.trim();

        UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(
                username, password);

        // Allow subclasses to set the "details" property
        setDetails(request, authRequest);

        return this.getAuthenticationManager().authenticate(authRequest);
    }

    @Nullable
    protected String obtainPassword(HttpServletRequest request) {
        return request.getParameter(passwordParameter);
    }

    @Nullable
    protected String obtainUsername(HttpServletRequest request) {
        return request.getParameter(usernameParameter);
    }

    protected void setDetails(HttpServletRequest request,
                              UsernamePasswordAuthenticationToken authRequest) {
        authRequest.setDetails(authenticationDetailsSource.buildDetails(request));
    }

	// ......其他略......
}

通过上述代码可以分析出如下结论

  1. 从构造方法中得知 该过滤器只针对**post请求的/login接口生效**, 在上面曾经说过在执行attemptAuthentication,之前会先调用requiresAuthentication()进行请求校验,校验的规则就是根据该构造器来决定的。
  2. 过滤器中,再利用obtainUsername和obtainPassword方法,提取出请求里边的用户名/密码,提取方式就是request.getParameter,这也是为什么SpringSecurity中默认的表单登录要通过key/value的形式传递参数,而不能传递JSON参数如果像传递JSON参数,我们可以通过修改这里的代码来进行实现;
  3. 获取到请求里传递来的用户名/密码之后,接下来会构造一个UsernamePasswordAuthenticationToken对象,传入username和password其中username对应了UsernamePasswordAuthenticationToken中的principal属性,而password则对应了它的credentials属性;
  4. 接下来再利用setDetails方法给details属性赋值,UsernamePasswordAuthenticationToken本身是没有details属性的,这个属性是在它的父类AbstractAuthenticationToken中定义的details是一个对象,这个对象里边存放的是WebAuthenticationDetails实例,该实例主要描述了请求的remoteAddress以及请求的sessionId这两个信息;
  5. 最后一步,就是利用AuthenticationManager对象来调用authenticate()方法去做认证校验;
AuthenticationManager与ProviderManager

在上面 UsernamePasswordAuthenticationFilter类的 attemptAuthentication() 方法中得知,该方法的最后一步会进行关于认证的校验,而要进行认证操作首先要获取到一个 AuthenticationManager 对象,这里默认拿到的是AuthenticationManager的子类ProviderManager ,如下图所示:
在这里插入图片描述

进入到 ProviderManager 的 authenticate()方法中,来看看认证到底是怎么实现的。比较重要的

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

以上四张截图就是ProviderManager认证相关的核心逻辑
Spring Security中关于认证的重要逻辑几乎都是在这里完成的

  1. 首先利用反射,获取到要认证的authentication对象的Class字节码
  2. 判断当前provider是否支持该authentication对象
    • 如果当前provider不支持该 authentication 对象,则退出当前判断,进行下一次判断。
    • 如果支持,则调用provider的authenticate方法开始做校验,校验完成后,会返回一个新的Authentication
  3. 这里如果 provider 的 authenticate 方法没能返回一个 Authentication 认证对象,则会调用 provider 的 parent 对象中的 authenticate 方法继续校验。
  4. 而如果通过了校验,返回了一个Authentication认证对象,则调用copyDetails()方法把旧Token的details属性拷贝到新的Token中,如下图;
  5. 接下来会调用eraseCredentials()方法来擦除凭证信息,也就是我们的密码,这个擦除方法比较简单,就是将Token中的credentials属性置空;
  6. 最后通过publishAuthenticationSuccess()方法将认证成功的事件广播出去;
  7. SpringSecurity会监听这个事件,接收到这个Authentication对象,进而调用SecurityContextHolder.getContext().setAuthentication(…)方法,将AuthenticationManager返回的Authentication对象,存储在当前的SecurityContext对象中;
AuthenticationProvider

AuthenticationManager是负责管理协调认证工作的,但并不负责认证功能的真正实现,认证功能的真正实现是由 AuthenticationManager 中引用的 AuthenticationProvider的子类来完成的,通过源码我们可以看到AuthenticationManager 中引用了一个providers列表,

private List<AuthenticationProvider> providers = Collections.emptyList();

providers集合的泛型是*AuthenticationProvider接口,*AuthenticationProvider接口有多个实现子类,如下图:

在这里插入图片描述

DaoAuthenticationProvider类关系

在这里插入图片描述

AuthenticationProvider接口的一个直接子类是AbstractUserDetailsAuthenticationProvider,该类又有一个直接子类DaoAuthenticationProvider。平常我们使用用户名密码登录时,默认就是使用该Provider。
Spring Security中默认就是使用DaoAuthenticationProvider来实现基于数据库模型认证授权工作的!

DaoAuthenticationProvider 在进行认证的时候,需要调用 UserDetailsService 对象的loadUserByUsername() 方法来获取用户信息 UserDetails,其中包括用户名、密码和所拥有的权限等。所以如果我们需要改变认证方式,可以实现自己的 AuthenticationProvider;如果需要改变认证的用户信息来源,我们可以实现 UserDetailsService。

DaoAuthenticationProvider类中并没有重写 authenticate() 方法,authenticate() 方法是在父类AbstractUserDetailsAuthenticationProvider中实现的。

public Authentication authenticate(Authentication authentication)
			throws AuthenticationException {
		......

		//获取authentication中存储的用户名
		String username = (authentication.getPrincipal() == null) ? "NONE_PROVIDED"
				: authentication.getName();

    	//判断是否使用了缓存
		boolean cacheWasUsed = true;
		UserDetails user = this.userCache.getUserFromCache(username);

		if (user == null) {
			cacheWasUsed = false;

			try {
                //retrieveUser()是一个抽象方法,由子类DaoAuthenticationProvider来实现,用于根据用户名查询用户。
				user = retrieveUser(username,
						(UsernamePasswordAuthenticationToken) authentication);
			}
			catch (UsernameNotFoundException notFound) {
				......
		}

		try {
            //进行必要的认证前和额外认证的检查
			preAuthenticationChecks.check(user);
            
            //这是抽象方法,由子类DaoAuthenticationProvider来实现,用于进行密码对比
			additionalAuthenticationChecks(user,
					(UsernamePasswordAuthenticationToken) authentication);
		}
		catch (AuthenticationException exception) {
			if (cacheWasUsed) {
				//在发生异常时,尝试着从缓存中进行对象的加载
				cacheWasUsed = false;
				user = retrieveUser(username,
						(UsernamePasswordAuthenticationToken) authentication);
				preAuthenticationChecks.check(user);
				additionalAuthenticationChecks(user,
						(UsernamePasswordAuthenticationToken) authentication);
			}
			else {
				throw exception;
			}
		}
		
        //认证后的检查操作
		postAuthenticationChecks.check(user);

		if (!cacheWasUsed) {
			this.userCache.putUserInCache(user);
		}

		Object principalToReturn = user;

		if (forcePrincipalAsString) {
			principalToReturn = user.getUsername();
		}
		
        //认证成功后,封装认证对象
		return createSuccessAuthentication(principalToReturn, authentication, user);
	}

查看源码我们可以知道大概的逻辑

  1. 首先会从Authentication提取出登录用户名

  2. 然后利用得到的username,先去缓存中查询是否有该用户

  3. 如果缓存中没有该用户,则去执行 retrieveUser() 方法获取当前用户对象。而这个retrieveUser()方法是个抽象方法,在AbstractUserDetailsAuthenticationProvider类中并没有实现,是由子类DaoAuthenticationProvider来实现的。
    在这里插入图片描述

  4. 在DaoAuthenticationProvider类的retrieveUser()方法中,会调用getUserDetailsService()方法,得到UserDetailsService对象,执行我们自己在登录时候编写的loadUserByUsername()方法,然后返回一个UserDetails对象,也就是我们的登录对象如下图所示;
    在这里插入图片描述

  5. 接下来会继续往下执行preAuthenticationChecks.check()方法,检验user中各账户属性是否正常,例如账户是否被禁用、是否被锁定、是否过期等

  6. 接着会继续往下执行additionalAuthenticationChecks()方法,进行密码比对。而该方法也是抽象方法,也是由子类DaoAuthenticationProvider进行实现。我们在注册用户时对密码加密之后,Spring Security就是在这里进行密码比对的******。如下所示。

在这里插入图片描述

  1. 然后在postAuthenticationChecks.check()方法中检查密码是否过期,如下所示;
  2. 然后判断是否进行了缓存,如果未进行缓存,则执行缓存操作,这个缓存是由SpringCacheBasedUserCache类来实现的;
    • 我们这里如果没有对缓存做配置,则会执行默认的缓存配置操作。如果我们对缓存进行了自定义的配置,比如配置了RedisCache,就可以把对象缓存到redis中。
  3. 最后通过createSuccessAuthentication()方法构建出一个新的 UsernamePasswordAuthenticationToken对象。

在这里插入图片描述

两张图疏通Spring Security认证流程 我们都知道实现一套Spring Security 的认证流程, 需要设计很多和类来回切换,等等, 这些类名又非常的长, 所以导致我们在写的时候,思绪混乱,不知道下一步应该写什么 ,所以今天我们就通过两张图来搞明白这个认证编码的流程Tip:最好自己是已经跟着文档或者视频做过一次Spring Security认证流程可以看看我的上一篇博客更加优雅的认证授权——Spring Security_Hzq958的博客-优快云博客所以我们的编码流程自顶向下的方式是非常合理, 避免了反复频繁的切换类。 阅读详情

相关推荐

使用SpringSecurity定义的登录认证

太久没有发过博客,总结一波SpringSecurity登录认证,记录每次的学习体验。。。。。。。。。。 实现WebSecurityConfigurerAdapter 配置安全框架 //@EnableWebSecurity 的 JavaConfig 配置类到 IoC 容器 @EnableWebSecurity // 启用方法级别的权限认证@EnableGlobalMethodSecurity(prePostEnabled = true) public class SpringSecu...

懒虫翻身的博客 1322

SpringSecurity的执行流程超详细讲解

如果不是的话做放行,如果是的话做认证,并调用子类的attemptAuthentication方法去查数据库返回UserDetails,把认证成功的数据封装到这个Authentication对象中去,并且做一个session策略的设置,当认证失败,做异常抛出,掉认证失败方法。注意看这里是一个try,catch,有成功就肯定有失败,这步就是如果认证失败,则抛出异常,执行认证失败的方法。默认为false,如果认证成功,则变为true,执行后续操作。方法,得到表单数据,进行身份认证,如果认证成功,返回一个。

qq_41473691的博客 5715

SpringSecurity授权流程源码分析

前言 在之前文章中有单独写过SpringSecurity表单登录流程源码分析,SpringSocial使用QQ授权登录流程详细分析两篇关于登录流程的,这些其实只是SpringSecurity整个流程的一部分罢了,也就是验证一下用户身份,但是真正的授权还是要这篇文章来讲解的!废话不多说,进入正题吧! 这张图是贯穿整个SpringSecurity的核心流程的,但是观看图可能理解是有点抽象,这篇文章就来详细解释这张流程图! 理论铺垫 SpringSecurity真正判断请求能否通过是在FilterSecurit

程序员劝退师的博客 546

Spring Security 中的执行原理流程分析

1.简介 Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。它提供了一组可以在Spring应用上下文中配置的Bean,充分利用了Spring IoC,DI(控制反转Inversion of Control ,DI:Dependency Injection 依赖注入)和AOP(面向切面编程)功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作。 2.认证授权分析 用户在进行资...

weixin_63835553的博客 3017

springsecurity原理流程图.pdf

SpringSecurity框架的权限认证流程原理,请求到来时SpringSecurity如果调用层层过滤器来完成认证;

从编解码芯片看Tesla T4的隐藏实力:双NVDEC如何实现70路1080P解码?

本文深入剖析了英伟达Tesla T4显卡的隐藏实力,重点解读其独特的双NVDEC硬件解码器设计如何突破性能瓶颈。通过分析Turing架构、对比HEVC/H.264解码差异,并结合驱动与SDK优化,揭示了实现高达70路1080P视频流并发解码的原理与实战配置,为云游戏、直播转码等高并发场景提供高效解决方案。

weixin_29209801的博客 485

springsecurity认证和授权

springsecurity

qq_45098321的博客 759

用Unity Wheel Collider做坦克转向?3步实现履带式载具物理效果

本文详细解析了如何利用Unity的Wheel Collider组件实现履带式载具的差速转向物理效果。通过思维转换、场景搭建和核心代码实现三步,将Wheel Collider从模拟轮式车辆转向改造为控制履带扭矩差的系统,并深入探讨了参数调试与真实感提升的方法,帮助开发者打造物理反馈扎实的坦克或特种车辆模拟。

weixin_29009971的博客 223

qtmd SpringSecurity(认证篇)

大白话讲SpringSecurity认证,小白专属。

weixin_48464872的博客 538

N32串口DMA接收不定长数据:空闲中断与DMA通道的协同处理

本文详细解析了在N32系列MCU中,利用串口空闲中断与DMA通道协同处理不定长数据的核心机制与实战方法。通过剖析空闲中断的触发时机、DMA的配置要点以及两者协同工作的关键时序,提供了避免数据错乱的避坑指南和完整的代码实现,旨在帮助开发者构建高效、可靠的嵌入式串口通信子系统。

weixin_29191669的博客 123

微生物16S数据上传NCBI的SRA库

本篇内容仅包括:俺自己的实验收集了淡水、淡水沉积物、海水、海草附着微生物样品,测序所得的Fastq格式数据,在文章投稿发表时被要求数据需上传NCBI的SRA库,得到一个PRJNA2347899这样子的IDs。仅解决了这个上传过程!

Xf_Niu的博客 7435

SpringSecurity(五):前后端分离认证总结案例。

前言难点分析Controller层eneity层RoleUserdao层service层config层resourcesmapperpropertiespom.xml结尾和上一篇一样,从上倒下复制粘贴,所有代码贴完再运行,代码没有问题,只要贴对,都可以顺利跑出来的。

左灯右行的爱情 1298

动态库加载失败终极指南:从libbz2.so.1错误看Linux依赖管理本质

本文以经典的libbz2.so.1加载错误为例,深入剖析Linux动态链接库管理的核心机制。文章不仅提供从ldd检查、符号链接创建到LD_LIBRARY_PATH设置等实战解决方案,更系统性地讲解了动态链接器的寻库路径、版本管理及依赖问题预防策略,帮助开发者从根本上理解和掌握Linux依赖管理本质。

weixin_29212429的博客 447

SpringSecurity+Jwt+Aouth2实现前后端分离的登录认证(有源码)

基于springSecurity的简易登录系统

qq_44993268的博客 4423

Spring Boot 实现多图片上传并回显,涨姿势了~

上传 Controller的代码非常简单,由于用了SpringMVC框架,所以直接用MultipartFile来接即可。由于是多图片上传所以用数组来接。此处应该注意参数名应该和<input>中的name值相对应: @RequestMapping("/pic") @ResponseBody publicResponseEntity<String>pic(MultipartFile[]pictures)throwsException{ ResponseEnti...

weixin_54556126的博客 894

从零到一:PrimeTime静态时序分析入门指南

本文详细介绍了PrimeTime静态时序分析(STA)的入门指南,从基础概念到实际应用全面覆盖。内容包括时序路径分类、PrimeTime环境搭建、时序约束设置与验证、时序分析与报告解读等核心内容,帮助工程师快速掌握STA技术,解决数字芯片设计中的时序收敛问题。

weixin_28730131的博客 268

2. SpringSecurity 自定义表单登录

在上一篇文章的结尾,我们列入了默认使用 SpringSecurity 一些待优化和解决的问题,我们再来回顾一下 用户登录不可能以这种弹框形式去登录,一般网页都有自己的登录页面(自定义登录页面) 用户名、密码应该是从数据库中读取,而不是默认和随机的(自定义认证逻辑) 并不是对所有的资源或接口都需要认证(设置资源白名单) 认证成功或者失败的处理,比如登录成功可以做一些记录,失败做一些处理 本篇文章...

Earth_Programer的博客 1003

(11-3-01 )

以太坊(Ethereum)是一种基于区块链技术的开源平台和加密货币。它于2015年由Vitalik Buterin和Gavin Wood等开发者创建,并成为比特币之后最受欢迎的加密货币之一。以太坊不仅支持加密货币交易,还为开发者和企业提供了构建去中心化应用程序的强大工具。在本节的内容中,将实型一个完整的机器学习模型项目,智能检测出以太坊区块链中的非法账户。从问题定义到模型建立和评估,再到最终的总结和建议。本实例突出了处理类别不平衡问题的重要性,并展示了如何使用多种机器学习算法来解决实际问题。此外,通过数据可

码农三叔 2170

Java实现手机验证码登录和SpringSecurity权限控制

由于身份受限,只能基于模拟的方式进行验证码发送,而不能通过手机短信实现(开通需要认证资质或上线项目) 2、后端生产验证码并保存到Redis中 3、手机登录后端代码编写 3.1、Controller登录控制器编写 页面登录够可以查看浏览器的Cookie是否有保存到用户的手机号信息查看Redis可视化工具查看保存的用户登录信息系统提供的用于识别用户身份的功能,通常提供用户名和密码进行登录其实就是在进行认证,认证的目的是让系统知道你是谁。用户认证成功后,需要为用户授权,其实就是指定当前用户可以

我要记录学习博客 2525

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

【springboot/springsecurity】session超时时间设置

文章目录1 springboot项目session超时时间设置2 springsecurity下如何通知用户session超时2.1 在配置文件BrowserSecurityConfig里加上session超时跳向的url2.2 在配置文件BrowserSecurityConfig里为指定session超时跳向的url授权2.3 写一个controller方法来处理session超时的提示逻辑2....

nrsc 2万+

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

SpringSecurity(一):权限管理设计与实现(官文英解+源码调试+基本环境搭建)

加油

左灯右行的爱情 1332

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

一文搞懂SpringSecurity---[Day05]anyRequest,antMatcher,regexMatchers,mvcMatchers详解

在Spring Security的配置类中配置 .servletPath() 是 mvcMatchers()返回值特有的方法,antMatchers()和 regexMatchers()没有这个方法。无论是 antMatchers() 还是 regexMatchers() 都具有两个参数的方法,其中第一个参数都是HttpMethod,表 示请求方式,当设置了 HttpMethod 后表示只有设定的特定的请求方式才执行对应的权限设置。参数是不定向参数,每一个参数是一个ant表达式,用于匹配URL规则。

ywb201314的专栏 1091

SpringSecurity权限管理系统实战—一、项目简介和开发环境准备

SpringSecurity实战一—项目简介和开发环境准备 一、简介 ​ 在企业应用中,认证和授权是非常重要的一部分内容,业界最出名的两个框架就是大名鼎鼎的 Shiro和Spring Security。本次我选取的是和SpringBoot更好兼容的SpringSecurity。

CoderMy的博客 2万+

Spring Security 核心解读(二)自定义认证授权体系

Spring Security 自定义认证授权

冰糖的博客 1266

springsecurity oauth2使用jwt实现单点登录

在如今前后端分离架构越来越成为开发的主流模式,因此以前基于session的权限管理已经不适合前后端分离架构了,springsecurityoauth2的出现帮我们解决了这个问题。本文采用springsecurityoauth2+jwt实现单点登录,适合前后端分离的项目。...

weixin_44837750的博客 1428

6.SpringSecurity自定义用户登录页面

上面的/user/login也可以换成/login,主要是以/login结尾。页面中的username,password不能修改,只能是固定值。

卷土的博客 1019
上一篇: MVCC简单了解学习
掰棒子的熊
博客等级 码龄7年 9粉丝 11原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值