Spring Security-02-Spring Security认证方式-HTTP基本认证、Form表单认证、HTTP摘要认证、前后端分离安全处理方案
Lison <dreamlison@163.com>, v1.0.0, 2024.06.01
Spring Security-02-Spring Security认证方式-HTTP基本认证、Form表单认证、HTTP摘要认证、前后端分离安全处理方案
文章目录
- Spring Security-02-Spring Security认证方式-HTTP基本认证、Form表单认证、HTTP摘要认证、前后端分离安全处理方案
- 认证方式
- HTTP基本认证
- 基本认证简介
- 基本认证核心API
- 基本认证的步骤
- 基本认证的弊端
- HTTP基本认证代码实现
- 创建SecurityConfig配置类
- 测试验证
- Basic认证详解
- 基本认证过程
- 注销Basic认证
- Form表单认证
- 表单认证简介
- 表单认证效果
- 表单认证中的预置url和页面
- 自定义表单认证配置
- 创建SecurityConfig配置类
- 测试应用
- 自定义表单认证的登录界面
- 服务端代码定义
- 页面定义
- 测试应用
- 细化表单认证配置
- 定义SecurityConfig类
- 自定义登录页面
- 定义错误处理页面
- 测试验证
- HTTP摘要认证
- HTTP摘要认证简介
- HTTP摘要认证核心参数
- 摘要认证代码实现
- 编写测试接口
- 创建SecurityConfig配置类
- 测试接口
- HTTP摘要认证弊端
- 前后端分离时的安全处理方案
- 前后端分离简介
- 认证处理时的相关API
- 页面跳转的相关API
- 返回JSON格式的处理器
- 认证成功时的处理方案
- 1. successHandler()方法
- 2. onAuthenticationSuccess参数
- 定义SecurityAuthenticationSuccessHandler类
- 配置successHandler
- 验证结果
- 认证失败时的处理方案
- failureHandler()
- 代码实现
- 配置failureHandler
- 验证结果
- 退出登录时的处理方案
- 1. logoutSuccessHandler()
- 2. 定义SecurityLogoutSuccessHandler类
- 配置logoutSuccessHandler
- 验证结果
- 未认证时的处理方案
- 1. authenticationEntryPoint()
- 2. 定义SecurityAuthenticationEntryPoint类
- 配置authenticationEntryPoint
- 验证结果
认证方式
认证: 所谓的认证,就是用来判断系统中是否存在某用户,并判断该用户的身份是否合法的过程,解决的其实是用户登录的问题。认证的存在,是为了保护系统中的隐私数据与资源,只有合法的用户才可以访问系统中的资源。
在Spring Security中,常见的认证方式可以分为HTTP层面和表单层面,常见的认证方式如下:
- HTTP基本认证;
- Form表单认证;
- HTTP摘要认证;
HTTP基本认证
基本认证简介
在Spring Security 4.x版本中,默认采用的登录方式是Http基本认证,该方式会弹出一个对话框,要求用户输入用户名和密码。在每次进行基本认证请求时,都会在Authorization请求头中利用Base64对 “用户:密码” 字符串进行编码。这种方式并不安全,并不适合在Web项目中使用,但它是一些现代主流认证的基础,而且在Spring Security的OAuth中,内部认证的默认方式就是用的Http基本认证。
基本认证核心API

执行流程如下:
Filter->构造Token->AuthenticationManager->转给Provider处理->认证处理成功后续操作或者不通过抛异常
基本认证的步骤
HTTP基本认证是在RFC2616标准中定义的一种认证模式,它以一种很简单的方式与用户进行交互。HTTP基本认证可以分为如下4个步骤:
- ①. 客户端首先发起一个未携带认证信息的请求;
- ②. 然后服务器端返回一个401 Unauthorized的响应信息,并在WWW-Authentication头部中说明认证形式:当进行HTTP基本认证时,WWW-Authentication会被设置为Basic realm=“被保护的页面”;
- ③. 接下来客户端会收到这个401 Unauthorized响应信息,并弹出一个对话框,询问用户名和密码。当用户输入后,客户端会将用户名和密码使用冒号进行拼接并用Base64编码,然后将其放入到请求的Authorization头部并发送给服务器;
- ④. 最后服务器端对客户端发来的信息进行解码得到用户名和密码,并对该信息进行校验判断是否正确,最终给客户端返回响应内容。
基本认证的弊端
HTTP基本认证是一种无状态的认证方式,与表单认证相比,HTTP基本认证是一种基于HTTP层面的认证方式,无法携带Session信息,也就无法实现Remember-Me功能。另外,用户名和密码在传递时仅做了一次简单的Base64编码,几乎等同于以明文传输,极易被进行密码窃听和重放攻击。所以在实际开发中,很少会使用这种认证方式来进行安全校验。
HTTP基本认证代码实现
创建SecurityConfig配置类
这里我们先创建一个config配置类,命名为SecurityConfig,并且继承自WebSecurityConfigurerAdapter父类,代码如下:
package com.lison.springsecurity.config.security;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;/*** @className: com.lison.springsecurity.config.security-> SecurityConfig* @description:* @author: Lison* @createDate: 2024-06-01*/
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {@Overrideprotected void configure(HttpSecurity http) throws Exception {//1.配置基本认证方式http.authorizeRequests()//对任意请求都进行认证.anyRequest().authenticated().and()//开启basic认证.httpBasic();}
}
httpBasic()方法,就是用来开启基本认证的,而且默认采用的就是基本认证!
测试验证
访问自己的/hello接口,这时候我们就可以看到浏览器中弹出了一个登陆窗口。提示我们输入自己的用户名和密码 lison/123456,认证成功后,即可访问自己的web接口。
Basic认证详解
基本认证过程
此时的响应码为401,什么情况下会导致401状态码?

根据401和以上响应头信息,浏览器会弹出一个对话框,要求输入 用户名/密码,Basic认证会将其拼接成 “用户名:密码” 格式,中间是一个冒号,并利用Base64编码成加密字符串xxx;然后在请求头中附加 Authorization: Basic xxx 信息,发送给后台认证;后台需要利用Base64来进行解码xxx,得到用户名和密码,再校验 用户名:密码 信息。
- 如果认证错误,浏览器会保持弹框;
- 如果认证成功,浏览器会缓存有效的Base64编码,在之后的请求中,浏览器都会在请求头中添加该有效编码。
注销Basic认证
在成功认证之后,Basic认证会把Authorization认证信息缓存在浏览器中一段时间,之后每次请求接口时都会自动带上,所以直到 用户关闭浏览器才会销毁认证信息,也就是说我们无法在服务端进行有效的注销。
不过在请求注销时,前端也可以手动 在请求头配置一个错误的Authorization,或者在浏览器的命令行执行 document.execuCommand(“ClearAuthenticationCache”)方法 来清空认证信息,但该方式对Chrome浏览器无效。我们在调试基本认证时,可以直接开启无痕模式,避免很多因为缓存造成的问题。
Form表单认证
表单认证简介
对于表单认证,其实在SpringBoot开发环境中,只要我们添加了Spring Security的依赖包,就会自动实现表单认证。在WebSecurityConfigurerAdapter类的config(HttpSecurity http)方法中,可以看到如下默认实现。

在SpringBoot环境中,默认支持的就是表单认证方式。
表单认证效果
第一个Spring Security项目中实现的效果,其实就是表单认证。每次我们在访问某个Web接口之前,都会重定向到一个Security自带的login登录页面上,这个登录页面,就是表单认证的效果

表单认证中的预置url和页面
这时候有的小伙伴可能就会很好奇,为什么表单认证会有以上效果?这是因为在默认的formLogin配置中,自动配置了一些url和页面:
- /login(get): get请求时会跳转到这个页面,只要我们访问任意一个需要认证的请求时,都会跳转到这个登录界面。
- /login(post): post请求时会触发这个接口,在登录页面点击登录时,默认的登录页面表单中的action就是关联这个login接口。
- /login?error: 当用户名或密码错误时,会跳转到该页面。
- /: 登录成功后,默认跳转到该页面,如果配置了index.html页面,则 ”/“ 会重定向到index.html页面,当然这个页面要由我们自己实现。
- /logout: 注销页面。
- /login?logout: 注销成功后跳转到的页面。
由此可见,SpringSecurity默认有两个login,即登录页面和登录接口的地址都是 /login:
- GET http://localhost:8080/login
- POST http://localhost:8080/login
如果是GET 请求,表示你想访问登录页面;如果是 POST 请求,表示你想提交登录数据。
对于这几个URL接口,我们简单了解即可。
自定义表单认证配置
创建SecurityConfig配置类
我们先编写一个类,继承自WebSecurityConfigurerAdapter父类,该类的作用如下:
- 验证所有请求;
- 允许用户使用表达登录进行身份验证;
- 允许用户使用Http基本认证
package com.lison.springsecurity.config.security;import org.springframework.context.annotation.Configuration;
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;/*** @className: com.lison.springsecurity.config.security-> SecurityConfig* @description:* @author: Lison* @createDate: 2024-06-01*/@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {@Overrideprotected void configure(HttpSecurity http) throws Exception {//配置表单认证方式http.authorizeRequests().anyRequest().authenticated().and()//开启表单认证.formLogin();}
}
SecurityConfig类上添加@EnableWebSecurity注解后,会自动被Spring发现并注册。在configure()方法中,我执行了formLogin()方法,该方法的功能就是开启表单认证。
测试应用
启动项目,访问我们定义的/hello接口时,首先会重定向到/login页面。输入自己配置的用户名和密码后,才可以正常访问/hello接口。

当认证成功后,内部再次发生了302重定向:可见从/login接口重定向到了/hello接口。
自定义表单认证的登录界面
Spring Security一个特点就在于可以高度自定义,灵活配置,可以自定义一个登录页面。
服务端代码定义
package com.lison.springsecurity.config.security;import org.springframework.context.annotation.Configuration;
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.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;/*** @className: com.lison.springsecurity.config.security-> SecurityConfig* @description:* @author: Lison* @createDate: 2024-06-01*/@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {/*** 用来定义哪些请求需要忽略安全控制,哪些请求必须接受安全控制;还可以在合适的时候清除SecurityContext以避免内存泄漏,* 同时也可以用来定义请求防火墙和请求拒绝处理器,另外我们开启Spring Security Debug模式也是这里配置的*/@Overridepublic void configure(WebSecurity web) throws Exception {//super.configure(web);web.ignoring().antMatchers("/js/**", "/css/**", "/images/**");}@Overrideprotected void configure(HttpSecurity http) throws Exception {//2.配置自定义的登录页面http.authorizeRequests().anyRequest().authenticated().and().formLogin()//加载自定义的登录页面地址.loginPage("/myLogin.html").permitAll().and()//注意:需禁用crsf防护功能,否则登录不成功.csrf().disable();}
}
1、WebSecurity执行流程

在configure(WebSecurity web)方法中,有个核心参数:WebSecurity类!在这个类里定义了一个securityFilterChainBuilders集合,可以同时管理多个SecurityFilterChain过滤器链,各位可以回顾我们学习Web基础时,关于过滤器的知识点,这些过滤器的执行是不是比Servlet更早?
当WebSecurity在执行时,会构建出一个名为 ”springSecurityFilterChain“ 的 Spring BeanFilterChainProxy代理类,它的作用是来 定义哪些请求可以忽略安全控制,哪些请求必须接受安全控制;以及在合适的时候 清除SecurityContext 以避免内存泄漏,同时也可以用来 定义请求防火墙和请求拒绝处理器,也可以在这里 开启Spring Security 的Debug模式。
上面这一系列的Filter过滤器,我们就可以利用web.ignoring() 方法来配置想要忽略的静态资源 URL 地址,这样这些静态资源就可以不被拦截,从而可以被识别访问
2、HttpSecurity作用;

HttpSecurity用来构建包含一系列的过滤器链SecurityFilterChain,平常我们的配置就是围绕着这个SecurityFilterChain进行。
页面定义
首先自定义一个登陆页面,主要是编写html代码和css样式,其核心代码如下:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Login Page</title><style>body {background-color: #f2f2f2;font-family: Arial, sans-serif;}.container {max-width: 400px;margin: 0 auto;padding: 40px;background-color: #fff;border-radius: 5px;box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);}h2 {text-align: center;margin-bottom: 30px;}.form-group {margin-bottom: 20px;}label {display: block;font-weight: bold;margin-bottom: 5px;}input[type="text"],input[type="password"] {width: 100%;padding: 10px;border: 1px solid #ccc;border-radius: 3px;}.btn {display: block;width: 100%;padding: 10px;background-color: #4caf50;color: #fff;font-weight: bold;text-align: center;text-decoration: none;border: none;border-radius: 3px;cursor: pointer;}.btn:hover {background-color: #45a049;}</style>
</head>
<body>
<div class="container"><h2>Login</h2><form action="/myLogin.html" method="post"><div class="form-group"><label for="username">Username:</label><input type="text" id="username" name="username" placeholder="Enter your username"></div><div class="form-group"><label for="password">Password:</label><input type="password" id="password" name="password" placeholder="Enter your password"></div><button class="btn" type="submit">Login</button></form>
</div>
</body>
</html>
测试应用
启动项目后,我们访问接口时,就会自动跳转到自己定义的/myLogin.html页面上,输入用户名和密码后,就可以成功访问自己的接口。

细化表单认证配置
修改表单认证页面中请求参数的名称,定义认证失败时的错误处理页面,处理退出登录时的操作等,这些都可以自定义配置,实现代码如下。
定义SecurityConfig类
package com.lison.springsecurity.config.security;import org.springframework.context.annotation.Configuration;
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.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;/*** @className: com.lison.springsecurity.config.security-> SecurityConfig* @description:* @author: Lison* @createDate: 2024-06-01*/@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {/*** 用来定义哪些请求需要忽略安全控制,哪些请求必须接受安全控制;还可以在合适的时候清除SecurityContext以避免内存泄漏,* 同时也可以用来定义请求防火墙和请求拒绝处理器,另外我们开启Spring Security Debug模式也是这里配置的*/@Overridepublic void configure(WebSecurity web) throws Exception {//super.configure(web);web.ignoring().antMatchers("/js/**", "/css/**", "/images/**");}@Overrideprotected void configure(HttpSecurity http) throws Exception {//super.configure(http);//3.进一步配置自定义的登录页面 //拦截请求,创建FilterSecurityInterceptor http.authorizeRequests().anyRequest().authenticated()//用and来表示配置过滤器结束,以便进行下一个过滤器的创建和配置.and()//设置表单登录,创建UsernamePasswordAuthenticationFilter.formLogin().loginPage("/myLogin.html").permitAll()//指登录成功后,是否始终跳转到登录成功url。它默认为false.defaultSuccessUrl("/index.html",true)//post登录接口,登录验证由系统实现.loginProcessingUrl("/login")//用户密码错误跳转接口.failureUrl("/error.html")//要认证的用户参数名,默认username.usernameParameter("username")//要认证的密码参数名,默认password.passwordParameter("password").and()//配置注销.logout()//注销接口.logoutUrl("/logout")//注销成功后跳转到的接口.logoutSuccessUrl("/myLogin.html").permitAll()//删除自定义的cookie.deleteCookies("myCookie").and()//注意:需禁用crsf防护功能,否则登录不成功.csrf().disable();}
}
自定义登录页面
登录页面也跟着修改一下,主要是把form表单中action的值修改掉为 login
<body>
<div class="container"><h2>Login</h2><form action="/login" method="post"><div class="form-group"><label for="username">Username:</label><input type="text" id="username" name="username" placeholder="Enter your username"></div><div class="form-group"><label for="password">Password:</label><input type="password" id="password" name="password" placeholder="Enter your password"></div><button class="btn" type="submit">Login</button></form>
</div>
</body>
注意:此时form表单中action的值,要写成”/login“,因为我们在配置类中通过“loginProcessingUrl(“/login”)”方法中做了明确的配置
定义错误处理页面
输入了错误的用户名和密码后,可以提供一个错误处理页面,当认证失败后跳转到这个页面即可
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<h1> ERROR 错误页面</h1>
</body>
</html>
测试验证
如果访问自己的接口,比如/hello,会先重定向到/myLogin.html页面,输入自己配置的用户名和密码,经过验证后,才会重定向到/index.html页面中,否则会重定向到我们配置的/error.html页面中。
1、重定向到/myLogin.html
访问资源时,会先重定向到自定义的登录页面。

2、重定向到/index.html
认证成功后,会重定向到index.html页面。

3、重定向到/error.html
认证失败后,会重定向到自定义的错误处理页面。

HTTP摘要认证
HTTP摘要认证简介
HTTP摘要认证和HTTP基本认证一样,也是在RFC2616中定义的一种认证方式,它的出现是为了弥补HTTP基本认证存在的安全隐患,但该认证方式也并不是很安全**。HTTP摘要认证会使用对通信双方来说都可知的口令进行校验,且最终以密文的形式来传输数据,所以相对于基本认证来说,稍微安全了一些。
HTTP摘要认证与基本认证类似,基于简单的“挑战-回应”模型。当发起一个未经认证的请求时,服务器会返回一个401回应,并给客户端返回与验证相关的参数,期待客户端依据这些参数继续做出回应,从而完成整个验证过程
HTTP摘要认证核心参数
服务端给客户端返回的验证相关参数如下:
- username: 用户名。
- password: 用户密码。
- realm: 认证域,由服务器返回。
- opaque: 透传字符串,客户端应原样返回。
- method: 请求的方法。
- nonce: 由服务器生成的随机字符串,包含过期时间(默认过期时间300s)和密钥。
- nc: 即nonce-count,指请求的次数,用于计数,防止重放攻击。qop被指定时,nc也必须被指定。
- cnonce: 客户端发给服务器的随机字符串,qop被指定时,cnonce也必须被指定。
- qop: 保护级别,客户端根据此参数指定摘要算法。若取值为 auth,则只进行身份验证;若取值为auth-int,则还需要校验内容完整性,默认的qop为auth。
- uri: 请求的uri。
- response: 客户端根据算法算出的摘要值,这个算法取决于qop。
- algorithm: 摘要算法,目前仅支持MD5。
- entity-body: 页面实体,非消息实体,仅在auth-int中支持。
通常服务器端返回的数据包括realm、opaque、nonce、qop等字段,如果客户端需要做出验证回应,就必须按照一定的算法得到一些新的数据并一起返回**。在以上各种参数中,对服务器而言,最重要的字段是nonce;对客户端而言,最重要的字段是response**。
摘要认证代码实现
编写测试接口
package com.lison.springsecurity.controller;import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;/*** @className: com.lison.springsecurity.controller-> IndexController* @description:* @author: Lison* @createDate: 2024-06-01*/
@RestController
public class IndexController {@GetMapping("/admin/hello")public String helloAdmin() {return "hello, admin";}@GetMapping("/user/hello")public String helloUser() {return "hello, user";}@GetMapping("/visitor/hello")public String helloVisitor() {return "hello, visitor";}}
创建SecurityConfig配置类
这里比较重要的是配置摘要认证入口端点DigestAuthenticationEntryPoint
package com.lison.springsecurity.config.security;import com.lison.springsecurity.service.MyUserDetailsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
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.authentication.www.DigestAuthenticationEntryPoint;
import org.springframework.security.web.authentication.www.DigestAuthenticationFilter;/*** @className: com.lison.springsecurity.config.security-> SecurityConfig* @description:* @author: Lison* @createDate: 2024-06-01*/
@EnableWebSecurity(debug = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {@Autowiredprivate DigestAuthenticationEntryPoint digestAuthenticationEntryPoint;@Autowiredprivate MyUserDetailsService userDetailsService;//配置认证入口端点,主要是设置认证参数信息@Beanpublic DigestAuthenticationEntryPoint digestAuthenticationEntryPoint(){DigestAuthenticationEntryPoint point=new DigestAuthenticationEntryPoint();point.setKey("Security Demos");point.setRealmName("lison");point.setNonceValiditySeconds(500);return point;}public DigestAuthenticationFilter digestAuthenticationFilter(){DigestAuthenticationFilter filter=new DigestAuthenticationFilter();filter.setAuthenticationEntryPoint(digestAuthenticationEntryPoint);filter.setUserDetailsService(userDetailsService);return filter;}@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().antMatchers("/admin/**").hasRole("ADMIN").antMatchers("/user/**").hasRole("USER").antMatchers("/visitor/**").permitAll().anyRequest().authenticated().and().csrf().disable()//当未认证时访问某些资源,则由该认证入口类来处理..exceptionHandling().authenticationEntryPoint(digestAuthenticationEntryPoint).and()//添加自定义过滤器到过滤器链中.addFilter(digestAuthenticationFilter());}}
测试接口
访问一下需要认证的接口/admin/hello接口,这时候会发现浏览器弹出了一个用户名密码的认证窗口。然后我们在浏览器中可以看到HTTP摘要认证信息,realm是我们自定义的“lison”,qop是默认的“auth”方式。

由此可见,此时摘要认证的方式已经生效。
HTTP摘要认证弊端
HTTP摘要认证与HTTP基本认证一样,都是基于HTTP层面的认证方式,也不能使用Session对象,因而也不支持Remember-Me功能。该方式虽然解决了HTTP基本认证中以明文传输密码的问题,但并未解决密码明文存储的问题,所以依然有安全隐患,所以在开发中,摘要认证的方式也不怎么使用。
以上三种认证方式,我们需要重点掌握表单认证;
前后端分离时的安全处理方案
前后端分离简介
企业开发中,前后端分离已成为互联网项目开发的业界标准方式,其核心思想就是前端HTML页面通过AJAX,调用后端的RESTFUL API接口,并使用JSON数据进行交互****。
该方式可以有效的在前后端项目之间进行解耦,并且前后端分离会为以后的大型分布式架构、弹性计算架构、微服务架构、多端化服务(多种客户端,例如 浏览器,车载终端,安卓,IOS等)打下坚实的基础。
认证处理时的相关API
页面跳转的相关API
1、登录成功时的跳转API
- defaultSuccessUrl
- successForwardUrl
2、登录失败时的跳转API
- failureUrl()
- failureForwardUrl()
返回JSON格式的处理器
在前后端分离模式下,既然后端没有页面,页面都在前端,那就可以考虑使用JSON来进行信息交互了,我们把认证成功或认证失败的信息,以JSON的格式传递给前端,由前端来决定到底该往哪个页面跳转;
我们要返回JSON格式的信息,有如下相关方法:
- successHandler()
- failureHandler()
- logoutSuccessHandler()
- authenticationEntryPoint()
- …
认证成功时的处理方案
相关的方法及其核心参数,即successHandler()和onAuthenticationSuccess参数。
1. successHandler()方法
successHandler()方法的功能十分强大,甚至也囊括了 defaultSuccessUrl()和 successForwardUrl() 的功能。
successHandler()方法的参数是一个 AuthenticationSuccessHandler 对象,这个对象中我们要实现的方法是 onAuthenticationSuccess()。
2. onAuthenticationSuccess参数
onAuthenticationSuccess() 方法中有三个参数,分别是:
- HttpServletRequest: 利用该参数我们可以实现服务端的跳转;
- HttpServletResponse: 利用该参数我们可以做客户端的跳转,也可以返回 JSON 数据;
- Authentication: 这个参数则保存了我们刚刚登录成功的用户信息。
定义SecurityAuthenticationSuccessHandler类
r认证成功后需要处理的类,要实现AuthenticationSuccessHandler 接口
/*** 处理登录成功时的业务逻辑*/
public class SecurityAuthenticationSuccessHandler implements AuthenticationSuccessHandler {/*** Authentication:携带登录的用户名及角色等信息*/@Overridepublic void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws ServletException, IOException {//直接输出json格式的响应信息Object principal = authentication.getPrincipal();response.setContentType("application/json;charset=utf-8");PrintWriter out = response.getWriter();//以json格式对外输出身份信息out.write(new ObjectMapper().writeValueAsString(principal));out.flush();out.close();}
}
配置successHandler
在SecurityConfig配置类中,调用successHandler()方法,把前面定义的SecurityAuthenticationSuccessHandler类关联进来
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().anyRequest().authenticated().and().formLogin().permitAll()//认证成功时的处理器.successHandler(new SecurityAuthenticationSuccessHandler()).and().csrf().disable();}}
验证结果
我们进行登录验证,在认证成功后,就可以看到登录成功的用户信息是通过 JSON 返回到前端的,如下图所示:

Spring Security会把认证的用户信息以JSON格式展示出来,比如我们的用户名、密码、角色等信息。
认证失败时的处理方案
相关的API方法及参数。
failureHandler()
failureHandler()方法的参数是一个 AuthenticationFailureHandler 对象,这个对象中我们要实现的方法是 onAuthenticationFailure()。
onAuthenticationFailure()方法有三个参数,分别是:
- HttpServletRequest: 利用该参数我们可以实现服务端的跳转;
- HttpServletResponse: 利用该参数我们可以做客户端的跳转,也可以返回 JSON 数据;
- AuthenticationException: 这个参数则保存了登录失败的原因。
代码实现
同样的,我们也要编写一个类SecurityAuthenticationFailureHandler,实现AuthenticationFailureHandler接口,来专门处理认证失败时的返回结果。
/*** 处理登录失败时的业务逻辑*/
public class SecurityAuthenticationFailureHandler implements AuthenticationFailureHandler {/*** AuthenticationException:异常信息*/@Overridepublic void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException, ServletException {//直接输出json格式的响应信息response.setContentType("application/json;charset=utf-8");PrintWriter out = response.getWriter();out.write(e.getMessage());out.flush();out.close();}
}
配置failureHandler
接着我们在SecurityConfig配置类中,调用failureHandler()方法来关联上面定义的SecurityAuthenticationFailureHandler类对象。
核心代码如下:
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().anyRequest().authenticated().and().formLogin().permitAll()//认证成功时的处理器.successHandler(new SecurityAuthenticationSuccessHandler())//认证失败时的处理器.failureHandler(new SecurityAuthenticationFailureHandler()).and().csrf().disable();}}
验证结果
配置完成后,我们再去登录,在认证失败时,就可以看到登录失败的用户信息通过 JSON 返回到前端了

退出登录时的处理方案
认证成功和认证失败后的处理方案后,退出登录后处理方案
1. logoutSuccessHandler()
负责退出登录的方法是logoutSuccessHandler(),这个方法中需要一个参数LogoutSuccessHandler;在LogoutSuccessHandler类中有一个方法 onLogoutSuccess(),该方法中的参数与登录成功时的参数一样。
2. 定义SecurityLogoutSuccessHandler类
我们先来定义一个SecurityLogoutSuccessHandler类,实现LogoutSuccessHandler接口,在这里负责输出退出登录时的JSON结果。
public class SecurityLogoutSuccessHandler implements LogoutSuccessHandler {@Overridepublic void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {response.setContentType("application/json;charset=utf-8");PrintWriter out = response.getWriter();out.write("注销成功");out.flush();out.close();}}
配置logoutSuccessHandler
然后我们在SecurityConfig配置类中,调用logoutSuccessHandler()方法来关联上面定义的SecurityLogoutSuccessHandler对象。
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().anyRequest().authenticated().and().formLogin().permitAll()//认证成功时的处理器.successHandler(new SecurityAuthenticationSuccessHandler())//认证失败时的处理器.failureHandler(new SecurityAuthenticationFailureHandler()).and().logout()//退出登录时的处理器.logoutSuccessHandler(new SecurityLogoutSuccessHandler()).and().csrf().disable();}}
验证结果
配置完成后,我们去访问/logout接口,退出登录成功,会有如下所示结果:

未认证时的处理方案
1. authenticationEntryPoint()
未认证时,同样有个专门的方法来处理,即authenticationEntryPoint()方法,这个方法中需要一个参数LoginUrlAuthenticationEntryPoint,在LoginUrlAuthenticationEntryPoint类中有一个方法 commence()。
2. 定义SecurityAuthenticationEntryPoint类
我们定义一个SecurityAuthenticationEntryPoint类,实现AuthenticationEntryPoint接口,在这里负责输出未认证时的JSON结果。
/*** @className: com.lison.springsecurity.config.security.handler-> SecurityAuthenticationEntryPoint* @description: 处理未登录认证时的响应信息* @author: Lison* @createDate: 2024-06-01*/
public class SecurityAuthenticationEntryPoint implements AuthenticationEntryPoint {@Overridepublic void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {response.setContentType("application/json;charset=utf-8");PrintWriter out = response.getWriter();out.write("尚未登录,请先登录");out.flush();out.close();}}
配置authenticationEntryPoint
然后我们在SecurityConfig配置类中,调用authenticationEntryPoint()方法来关联上面定义的SecurityAuthenticationEntryPoint对象。
验证结果
配置完成后,我们在未登录时,直接去访问项目中的某个接口,就会看到未登录时返回的JSON信息,如下图所示:

相关文章:
Spring Security-02-Spring Security认证方式-HTTP基本认证、Form表单认证、HTTP摘要认证、前后端分离安全处理方案
Lison <dreamlison163.com>, v1.0.0, 2024.06.01 Spring Security-02-Spring Security认证方式-HTTP基本认证、Form表单认证、HTTP摘要认证、前后端分离安全处理方案 文章目录 Spring Security-02-Spring Security认证方式-HTTP基本认证、Form表单认证、HTTP摘要认证、…...
【scikit-learn 1.2版本后】sklearn.datasets中load_boston报错 使用 fetch_openml 函数来加载波士顿房价
ImportError: load_boston has been removed from scikit-learn since version 1.2. 由于 load_boston 已经在 scikit-learn 1.2 版本中被移除,需要使用 fetch_openml 函数来加载波士顿房价数据集。 # 导入sklearn数据集模块 from sklearn import datasets # 导入波…...
vxe-table v4.8+ 与 v3.10+ 导出 xlsx、支持导出合并、设置样式、宽高、边框、字体、背景、超链接、图片的详细介绍,一篇就够了
Vxe UI vue vxe-table v4.8 与 v3.10 导出 xlsx、支持导出合并、设置样式、宽高、边框、字体、背景、超链接、图片等、所有常用的 Excel 格式都能自定义,使用非常简单,纯前端实现复杂的导出。 安装插件 npm install vxe-pc-ui4.2.39 vxe-table4.8.0 vx…...
江协科技STM32学习- P36 SPI通信外设
🚀write in front🚀 🔎大家好,我是黄桃罐头,希望你看完之后,能对你有所帮助,不足请指正!共同学习交流 🎁欢迎各位→点赞👍 收藏⭐️ 留言📝…...
【大数据】ClickHouse常见的表引擎及建表语法
ClickHouse 中最强大的表引擎当属 MergeTree (合并树)引擎及该系列(*MergeTree)中的其他引擎。接下来我们就仔细了解下MergeTree 及该系列的其他引擎的使用场景及建表语法。 MergeTree MergeTree 系列的引擎被设计用于插入极大量…...
explain执行计划分析 ref_
这里写目录标题 什么是ExplainExplain命令扩展explain extendedexplain partitions 两点重要提示本文示例使用的数据库表Explain命令(关键字)explain简单示例explain结果列说明【id列】【select_type列】【table列】【type列】 【possible_keys列】【key列】【key_len列】【ref…...
网络学习/复习4传输层
1,0...
Notepad++ 更改字体大小和颜色
前言 在长时间编程或文本编辑过程中,合适的字体大小和颜色可以显著提高工作效率和减少眼睛疲劳。Notepad 提供了丰富的自定义选项,让你可以根据个人喜好调整编辑器的外观。 步骤详解 1. 更改字体大小 打开 Notepad 启动 Notepad 编辑器。 进入设置菜…...
基于SSM+小程序的宿舍管理系统(宿舍1)
👉文末查看项目功能视频演示获取源码sql脚本视频导入教程视频 1、项目介绍 本宿舍管理系统小程序有管理员和学生两个角色。 1、管理员功能有个人中心,公告信息管理,班级管理,学生管理,宿舍信息管理,宿舍…...
【案例分享】TeeChart 如何为人类绩效解决方案提供数据洞察
“过去二十年来,我们一直在使用 Steema Software 产品,尤其是 TeeChart,这是我们软件开发的基础部分。看到 TeeChart 在这段时间里不断发展、改进和增加功能,真是太棒了,这极大地增强了我们的产品。Steema 的客户和技术…...
细谈 Linux 中的多路复用epoll
大家好,我是 V 哥。在 Linux 中,epoll 是一种多路复用机制,用于高效地处理大量文件描述符(file descriptor, FD)事件。与传统的select和poll相比,epoll具有更高的性能和可扩展性,特别是在大规模…...
51c自动驾驶~合集4
我自己的原文哦~ https://blog.51cto.com/whaosoft/12413878 #MCTrack 迈驰&旷视最新MCTrack:KITTI/nuScenes/Waymo三榜单SOTA paper:MCTrack: A Unified 3D Multi-Object Tracking Framework for Autonomous Driving code:https://gi…...
回归预测 | MATLAB实现BO-BiGRU贝叶斯优化双向门控循环单元多输入单输出回归预测
要在MATLAB中实现BO-BiGRU(贝叶斯优化双向门控循环单元)进行多输入单输出回归预测,您需要执行以下步骤: 数据准备:准备您的训练数据和测试数据。 模型构建:构建BO-BiGRU模型,可以使用MATLAB中的…...
2-ARM Linux驱动开发-设备树平台驱动
一、概述 设备树(Device Tree)是一种描述硬件的数据结构,用于将硬件设备的信息传递给操作系统内核。它的主要作用是使内核能够以一种统一、灵活的方式了解硬件平台的细节,包括设备的拓扑结构、资源分配(如内存地址、中断号等)等信…...
C语言函数与递归
函数 函数是指将一组能完成一个功能或多个功能的语句放在一起的代码结构。在C语言程序中,至少会包含一个函数,主函数main()。本章将详细讲解关于函数的相关内容。 1、库函数 ⭕️C语言库函数是指在C语言标准库中预先定义好的函数,这些函数包…...
Linux下的Debugfs
debugfs 1. 简介 类似sysfs、procfs,debugfs 也是一种内存文件系统。不过不同于sysfs一个kobject对应一个文件,procfs和进程相关的特性,debugfs的灵活度很大,可以根据需求对指定的变量进行导出并提供读写接口。debugfs又是一个Li…...
【FFmpeg】调整音频文件的音量
1、调整音量的命令 1)音量调整为当前音量的十倍 ffmpeg -i inputfile -vol 1000 outputfile 2)音量调整为当前音量的一半 ffmpeg -i input.wav -filter:a "volume=0.5" output.wav3)静音 ffmpeg -i input.wav -filter:a "volume=0" output.wav4)…...
mac 打开访达快捷键
一、使用快捷键组合 1. Command N 在当前桌面或应用程序窗口中,按下“Command N”组合键可以快速打开一个新的访达窗口。这就像在 Windows 系统中通过“Ctrl N”打开新的资源管理器窗口一样。 2. Command Tab 切换 如果访达已经打开,只是被其他应…...
Ubuntu学习笔记 - Day2
文章目录 学习目标:学习内容:学习笔记:Linux系统启动过程内核引导运行init运行级别系统初始化建立终端用户登录系统 Ubuntu关机关机流程相关命令 Linux系统目录结构查看目录目录结构 文件基本属性读写权限命令 下载文件的方法安装wget工具下载…...
c++基础12比较/逻辑运算符
比较/逻辑运算符 布尔比较运算符逻辑运算符位运算符(也用于逻辑运算)1<a<10怎么表达T140399判断是否为两位数代码 布尔 在C中,布尔类型是一种基本数据类型,用于表示逻辑值,即真(true)或假…...
Android Wi-Fi 连接失败日志分析
1. Android wifi 关键日志总结 (1) Wi-Fi 断开 (CTRL-EVENT-DISCONNECTED reason3) 日志相关部分: 06-05 10:48:40.987 943 943 I wpa_supplicant: wlan0: CTRL-EVENT-DISCONNECTED bssid44:9b:c1:57:a8:90 reason3 locally_generated1解析: CTR…...
多模态2025:技术路线“神仙打架”,视频生成冲上云霄
文|魏琳华 编|王一粟 一场大会,聚集了中国多模态大模型的“半壁江山”。 智源大会2025为期两天的论坛中,汇集了学界、创业公司和大厂等三方的热门选手,关于多模态的集中讨论达到了前所未有的热度。其中,…...
Cesium1.95中高性能加载1500个点
一、基本方式: 图标使用.png比.svg性能要好 <template><div id"cesiumContainer"></div><div class"toolbar"><button id"resetButton">重新生成点</button><span id"countDisplay&qu…...
【网络安全产品大调研系列】2. 体验漏洞扫描
前言 2023 年漏洞扫描服务市场规模预计为 3.06(十亿美元)。漏洞扫描服务市场行业预计将从 2024 年的 3.48(十亿美元)增长到 2032 年的 9.54(十亿美元)。预测期内漏洞扫描服务市场 CAGR(增长率&…...
页面渲染流程与性能优化
页面渲染流程与性能优化详解(完整版) 一、现代浏览器渲染流程(详细说明) 1. 构建DOM树 浏览器接收到HTML文档后,会逐步解析并构建DOM(Document Object Model)树。具体过程如下: (…...
基于Docker Compose部署Java微服务项目
一. 创建根项目 根项目(父项目)主要用于依赖管理 一些需要注意的点: 打包方式需要为 pom<modules>里需要注册子模块不要引入maven的打包插件,否则打包时会出问题 <?xml version"1.0" encoding"UTF-8…...
IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)
文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...
实现弹窗随键盘上移居中
实现弹窗随键盘上移的核心思路 在Android中,可以通过监听键盘的显示和隐藏事件,动态调整弹窗的位置。关键点在于获取键盘高度,并计算剩余屏幕空间以重新定位弹窗。 // 在Activity或Fragment中设置键盘监听 val rootView findViewById<V…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
R语言速释制剂QBD解决方案之三
本文是《Quality by Design for ANDAs: An Example for Immediate-Release Dosage Forms》第一个处方的R语言解决方案。 第一个处方研究评估原料药粒径分布、MCC/Lactose比例、崩解剂用量对制剂CQAs的影响。 第二处方研究用于理解颗粒外加硬脂酸镁和滑石粉对片剂质量和可生产…...
