Spring Security 接入 SpringBoot 与前后端分离实战
本文详解 Spring Security 在 Spring Boot 中的应用。内容包括核心概念、依赖引入、内存与数据库用户认证、BCrypt 密码加密、JWT 无状态认证流程及过滤器实现。此外还涵盖前后端分离场景下的登录授权、自定义安全处理器及权限控制策略,提供完整的安全防护方案。

本文详解 Spring Security 在 Spring Boot 中的应用。内容包括核心概念、依赖引入、内存与数据库用户认证、BCrypt 密码加密、JWT 无状态认证流程及过滤器实现。此外还涵盖前后端分离场景下的登录授权、自定义安全处理器及权限控制策略,提供完整的安全防护方案。

Spring Security 是一个强大且可扩展的框架,用于保护 Java 应用程序,尤其是基于 Spring 的应用。它提供了身份验证(验证用户身份)、授权(管理用户权限)和防护机制(如 CSRF 保护和防止会话劫持)等功能。
Spring Security 允许开发者通过灵活的配置实现安全控制,确保应用程序的数据和资源安全。通过与其他 Spring 生态系统的无缝集成,Spring Security 成为构建安全应用的理想选择。
当我们引入 security 依赖后,访问需要授权的 url 时,会重定向到 login 页面(security 自己创建的),login 页面需要账号密码,账号默认是 user, 密码是随机的字符串,在 spring 项目的输出信息中。
<!-- https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt-jackson -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.12.6</version>
<scope>runtime</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt-impl -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.12.6</version>
<scope>runtime</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt-api -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.12.6</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-security -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
<version>3.3.4</version>
</dependency>
一般我们会创建一个 SecurityConfig 类,来管理所有与 security 相关的配置。(我们讲的是 security 5.7 版本之后的配置方法,之前的方法跟现在不太一样)
@Configuration
@EnableWebSecurity
// 该注解启用 Spring Security 的 web 安全功能。
public class SecurityConfig {}
下面的都要写到 SecurityConfig 类中。
通过 createUser, manager 把用户配置的账号密码添加到 spring 的内存中,InMemoryUserDetailsManager 类中有一个 loadUserByUsername 的方法通过账号(username)从内存中获取我们配置的账号密码,之后调用其他方法来判断前端用户输入的密码和内存中的密码是否匹配。
@Bean
public UserDetailsService userDetailsService() {
// 创建基于内存的用户信息管理器
InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
manager.createUser(
// 创建 UserDetails 对象,用于管理用户名、用户密码、用户角色、用户权限等内容
User.withDefaultPasswordEncoder()
.username("user")
.password("user123")
.roles("USER")
.build()
);
// 如果自己配置的有账号密码,那么上面讲的 user 和 随机字符串 的默认密码就不能用了
return manager;
}
当我们点进 InMemoryUserDetailsManager 中 可以发现它实现了 UserDetailsManager 和 UserDetailsPasswordService 接口,其中 UserDetailsManager 接口继承的 UserDetailsService 接口中就有 loadUserByUsername 方法。
上面讲到,spring security 是通过 loadUserByUsername 方法来获取 User 并用这个 User 来判断用户输入的密码是否正确。所以我们只需要继承 UserDetailsService 接口并重写 loadUserByUsername 方法即可。
下面的样例我用的 mybatis-plus 来查询数据库中的 user, 然后通过当前查询到的 user 返回特定的 UserDetails 对象。
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
@Autowired
UserMapper userMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("username", username);
// 这里不止可以用 username,你可以自定义,主要根据你自己写的查询逻辑
User user = userMapper.selectOne(queryWrapper);
if (user == null) {
throw new UsernameNotFoundException(username);
}
return new UserDetailsImpl(user);
}
}
UserDetailsImpl 是实现了 UserDetails 接口的类。UserDetails 接口是 Spring Security 身份验证机制的基础,通过实现该接口,开发者可以定义自己的用户模型,并提供用户相关的信息,以便进行身份验证和权限检查。
@Data
@AllArgsConstructor
@NoArgsConstructor
// 这三个注解可以帮我们自动生成 get、set、有参、无参构造函数
public class UserDetailsImpl implements UserDetails {
private User user;
// 通过有参构造函数填充赋值的
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return List.of();
}
@Override
public String getPassword() {
return user.getPassword();
}
@Override
public String getUsername() {
return user.getUsername();
}
@Override
public boolean isAccountNonExpired() {
// 检查账户是否 没过期。
return true;
}
@Override
public boolean isAccountNonLocked() {
// 检查账户是否 没有被锁定。
return true;
}
@Override
public boolean isCredentialsNonExpired() {
//检查凭据(密码)是否 没过期。
return true;
}
@Override
public boolean isEnabled() {
// 检查账户是否启用。
return true;
}
// 这个方法是 @Data 注解 会自动帮我们生成,用来获取 loadUserByUsername 中最后我们返回的创建 UserDetailsImpl 对象时传入的 User。
// 如果你的字段包含 username 和 password 的话可以用强制类型转换,把 UserDetailsImpl 转换成 User。如果不能强制类型转换的话就需要用到这个方法了
public User getUser() {
return user;
}
}
下面这个是 security 的默认配置。我们可以修改并把它加到 spring 容器中,完成我们特定的需求。
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
// 开启授权保护。
.authorizeHttpRequests(authorize -> authorize
// 不需要认证的地址有哪些。
.requestMatchers("/blog/**", "/public/**", "/about").permitAll()
// ** 通配符
// 对所有请求开启授权保护。
.anyRequest().authenticated())
// 使用默认的登陆登出页面进行授权登陆。
.formLogin(Customizer.withDefaults())
// 启用'记住我'功能的。允许用户在关闭浏览器后,仍然保持登录状态,直到他们主动注销或超出设定的过期时间。
.rememberMe(Customizer.withDefaults());
// 关闭 csrf CSRF(跨站请求伪造)是一种网络攻击,攻击者通过欺骗已登录用户,诱使他们在不知情的情况下向受信任的网站发送请求。
http.csrf(csrf -> csrf.disable());
return http.build();
}
关于上面放行路径写法的一些细节问题:
如果在 application.properties 中配置的有 server.servlet.context-path=/api 前缀的话,在放行路径中不需要写 /api。
如果 @RequestMapping(value = "/test/") 中写的是 /test/, 那么放行路径必须也写成 /test/, (/test)是不行的,反之亦然。
如果 @RequestMapping(value = "/test") 链接 /test 后面要加查询字符的话(/test?type=0),不要写成 @RequestMapping(value = "/test/")。
上面都是一些细节问题,但是遇到 bug 的时候不容易发现。
下面这个是我常用的配置,配置了 jwt,加密的类,过滤器启用 jwt,而不是 session。(jwt 的类会在下面讲到)
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Autowired
private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration authConfig) throws Exception {
return authConfig.getAuthenticationManager();
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf(CsrfConfigurer::disable)
// 基于 token,不需要 csrf。
.sessionManagement((session) -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
// 基于 token,不需要 session。
.authorizeHttpRequests((authz) -> authz
.requestMatchers("/login/", "/getPicCheckCode").permitAll()
// 放行 api。
.requestMatchers(HttpMethod.OPTIONS).permitAll()
.anyRequest().authenticated())
.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
return http.build();
}
}
Spring Security 提供了多种加密和安全机制来保护用户的敏感信息,尤其是在用户身份验证和密码管理方面。(我们只讲默认的 BCryptPasswordEncoder)
在应用程序中,用户密码是最敏感的数据之一。为了防止密码泄露,即使数据库被攻击者获取,密码也应以加密形式存储。加密可以保护用户的隐私,并在一定程度上增加安全性。
Spring Security 提供了 PasswordEncoder 接口,用于定义密码的加密和验证方法。主要有以下几种实现:
BCrypt 是一种安全的密码哈希算法,具有以下特点:
可以在 Spring Security 的配置类中定义 PasswordEncoder bean,例如:
@Configuration
public class SecurityConfig {
@Bean
public PasswordEncoder passwordEncoder() {
// 也可用有参构造,取值范围是 4 到 31,默认值为 10。数值越大,加密计算越复杂
return new BCryptPasswordEncoder();
}
}
在注册用户或更新密码时,可以使用 PasswordEncoder 来加密密码:
@Autowired
private PasswordEncoder passwordEncoder;
public void registerUser(String username, String rawPassword) {
String encryptedPassword = passwordEncoder.encode(rawPassword);
// 保存用户信息到数据库,包括加密后的密码
}
在用户登录时,可以使用 matches 方法验证输入的密码与存储的加密密码是否匹配:
public boolean login(String username, String rawPassword) {
// 从数据库中获取用户信息,包括加密后的密码
String storedEncryptedPassword = // 从数据库获取;
return passwordEncoder.matches(rawPassword, storedEncryptedPassword);
}
POST /api/login)。AuthenticationManager 进行身份验证。localStorage 或 sessionStorage 中,以便后续请求使用。fetch('/api/protected-endpoint', {
method: 'GET',
headers: {
'Authorization': `Bearer ${token}`
}
});
OncePerRequestFilter 以拦截请求,提取 JWT,并验证其有效性。由于 JWT 是无状态的,后端不需要记录会话状态。用户可以通过前端操作(例如,删除存储的 JWT)来'退出登录'。可以实现一个注销接口,用于前端执行相关逻辑。
OncePerRequestFilter 是 Spring Security 提供的一个抽象类,确保在每个请求中只执行一次特定的过滤逻辑。它是实现自定义过滤器的基础,通常用于对请求进行预处理或后处理。(实现 JWT 会用到这个接口)实现:继承 OncePerRequestFilter 类,并重写 doFilterInternal 方法。
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class CustomFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
// 自定义过滤逻辑,例如记录请求日志
System.out.println("Request URI: " + request.getRequestURI());
// 继续执行过滤链
filterChain.doFilter(request, response);
}
}
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.addFilterBefore(new CustomFilter(), UsernamePasswordAuthenticationFilter.class);
// 其他配置...
return http.build();
}
}
基于我们上面引入的三个 JWT 相关的依赖,写 JwtUtil 类。
JwtUtil 类提供了生成和解析 JWT 的功能,是实现基于 JWT 的认证和授权的重要工具。@Component
public class JwtUtil {
public static final long JWT_TTL = 60 * 60 * 1000L * 24 * 14; // 有效期 14 天
public static final String JWT_KEY = "SDFGjhdsfalshdfHFdsjkdsfds121232131afasdfac";
public static String getUUID() {
return UUID.randomUUID().toString().replaceAll("-", "");
}
public static String createJWT(String subject) {
JwtBuilder builder = getJwtBuilder(subject, null, getUUID());
return builder.compact();
}
private static JwtBuilder getJwtBuilder(String subject, Long ttlMillis, String uuid) {
SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
SecretKey secretKey = generalKey();
long nowMillis = System.currentTimeMillis();
Date now = new Date(nowMillis);
if (ttlMillis == null) { ttlMillis = JwtUtil.JWT_TTL; }
long expMillis = nowMillis + ttlMillis;
Date expDate = new Date(expMillis);
return Jwts.builder()
.id(uuid)
.subject(subject)
.issuer("sg")
.issuedAt(now)
.signWith(secretKey)
.expiration(expDate);
}
public static SecretKey generalKey() {
byte[] encodeKey = Base64.getDecoder().decode(JwtUtil.JWT_KEY);
return new SecretKeySpec(encodeKey, 0, encodeKey.length, "HmacSHA256");
}
public static Claims parseJWT(String jwt) throws Exception {
SecretKey secretKey = generalKey();
return Jwts.parserBuilder().setSigningKey(secretKey).build().parseClaimsJws(jwt).getBody();
}
}
@Component:将这个类标记为 Spring 组件,允许 Spring 管理该类的生命周期,便于依赖注入。JWT_TTL:JWT 的有效期,设置为 14 天(单位为毫秒)。JWT_KEY:用于签名的密钥字符串,经过 Base64 编码。它是生成和验证 JWT 的关键。public static String getUUID() {
return UUID.randomUUID().toString().replaceAll("-", "");
}
jti),确保每个 JWT 都是唯一的。public static String createJWT(String subject) {
JwtBuilder builder = getJwtBuilder(subject, null, getUUID());
return builder.compact();
}
subject 是 JWT 的主题,通常是用户的身份信息。getJwtBuilder 方法生成一个 JWT 构建器,并将其压缩为字符串返回。private static JwtBuilder getJwtBuilder(String subject, Long ttlMillis, String uuid) {
// ...
}
setId(uuid):设置 JWT 的唯一标识。setSubject(subject):设置 JWT 的主题。setIssuer("sg"):设置 JWT 的发行者,通常是你的应用或服务名称。setIssuedAt(now):设置 JWT 的签发时间。signWith(signatureAlgorithm, secretKey):使用指定的算法和密钥进行签名。setExpiration(expDate):设置 JWT 的过期时间。public static SecretKey generalKey() {
byte[] encodeKey = Base64.getDecoder().decode(JwtUtil.JWT_KEY);
return new SecretKeySpec(encodeKey, 0, encodeKey.length, "HmacSHA256");
}
JWT_KEY 进行 Base64 解码,生成一个 SecretKey 对象,用于 JWT 的签名和验证。使用 HMAC SHA-256 算法进行签名。public static Claims parseJWT(String jwt) throws Exception {
SecretKey secretKey = generalKey();
return Jwts.parserBuilder().setSigningKey(secretKey).build().parseClaimsJws(jwt).getBody();
}
jwt 是要解析的 JWT 字符串。Claims 对象),其中包含了 JWT 的主题、发行者、过期时间等信息。先加一个依赖 JetBrains Java Annotations, 下面的代码会用到其中的一个注解 @NotNull。
这个 JwtAuthenticationTokenFilter 类是一个实现了 OncePerRequestFilter 接口自定义的 Spring Security 过滤器。
JwtAuthenticationTokenFilter 通过 JWT 对用户进行身份验证,确保请求中携带的 JWT 是有效的,并根据 JWT 提供的用户信息设置认证状态。import io.jsonwebtoken.Claims;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
@Autowired
private UserMapper userMapper;
@Override
protected void doFilterInternal(HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull FilterChain filterChain) throws ServletException, IOException {
String token = request.getHeader("Authorization");
if (!StringUtils.hasText(token) || !token.startsWith("Bearer ")) {
filterChain.doFilter(request, response);
return;
}
token = token.substring(7);
String userid;
try {
Claims claims = JwtUtil.parseJWT(token);
userid = claims.getSubject();
} catch (Exception e) {
throw new RuntimeException(e);
}
User user = userMapper.selectById(Integer.parseInt(userid));
if (user == null) {
throw new RuntimeException("用户名未登录");
}
UserDetailsImpl loginUser = new UserDetailsImpl(user);
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginUser, null, null);
// 如果是有效的 jwt,那么设置该用户为认证后的用户
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
filterChain.doFilter(request, response);
}
}
@Component:标记该类为 Spring 组件,使其能够被 Spring 扫描并注册到应用上下文中。OncePerRequestFilter:确保每个请求只调用一次该过滤器,适合进行请求预处理。@Autowired
private UserMapper userMapper;
UserMapper:一个数据访问对象(DAO),用于与数据库交互,以便根据用户 ID 查询用户信息。通过 Spring 的依赖注入机制自动注入。String token = request.getHeader("Authorization");
if (!StringUtils.hasText(token) || !token.startsWith("Bearer ")) {
filterChain.doFilter(request, response);
return;
}
Authorization 字段的值,检查是否包含 JWT。filterChain.doFilter(request, response) 继续执行下一个过滤器,返回。token = token.substring(7); // 去掉 "Bearer " 前缀
String userid;
try {
Claims claims = JwtUtil.parseJWT(token);
userid = claims.getSubject();
} catch (Exception e) {
throw new RuntimeException(e);
}
JwtUtil.parseJWT(token) 解析 JWT,提取出用户 ID (userid)。如果解析失败,会抛出异常。User user = userMapper.selectById(Integer.parseInt(userid));
if (user == null) {
throw new RuntimeException("用户名未登录");
}
UserDetailsImpl loginUser = new UserDetailsImpl(user);
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginUser, null, null);
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
UserDetailsImpl 对象,将查询到的用户信息封装。UsernamePasswordAuthenticationToken 对象,表示用户的认证信息,并将其设置到 Spring Security 的 SecurityContextHolder 中,以便后续请求能够访问到用户的认证信息。filterChain.doFilter(request, response);
filterChain.doFilter(request, response),继续执行后续的过滤器和最终的请求处理。JwtAuthenticationTokenFilter 过滤器把我们的过滤器应用到 spring security 中
http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
将 AuthenticationManager 对象添加到 spring 容器中。(添加到我们创建的 SecurityConfig 配置类中)
@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration authConfig) throws Exception {
return authConfig.getAuthenticationManager();
}
@Autowired
private AuthenticationManager authenticationManager;
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, password);
// 从数据库中对比查找,如果找到了会返回一个带有认证的封装后的用户,否则会报错,自动处理。(这里我们假设我们配置的 security 是基于数据库查找的)
Authentication authenticate = authenticationManager.authenticate(authenticationToken);
// 获取认证后的用户
User user = (User) authenticate.getPrincipal();
// 如果强制类型转换报错的话,可以用我们实现的 `UserDetailsImpl` 类中的 getUser 方法了
String jwt = JwtUtil.createJWT(user.getId().toString());
以下是获取当前用户认证信息的具体步骤:
// SecurityContextHolder 是一个存储安全上下文的工具类,提供了一个全局访问点,用于获取当前请求的安全上下文。
// SecurityContext 是当前线程的安全上下文,包含了当前用户的认证信息(即 Authentication 对象)。
SecurityContext context = SecurityContextHolder.getContext();
Authentication authentication = context.getAuthentication();
User user = (User) authenticate.getPrincipal();
// 另一种获取 User 的方法
UsernamePasswordAuthenticationToken authenticationToken = (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();
UserDetailsImpl loginUser = (UserDetailsImpl) authenticationToken.getPrincipal();
User user = userDetails.getUser();
authenticationManager 和 SecurityContext 获取 AuthenticationSecurityContextHolder.getContext().getAuthentication():
Authentication 对象。authenticationManager.authenticate(authenticationToken):
Authentication 对象,或者抛出异常。Authentication 接口包含以下重要方法:
getPrincipal():返回当前用户的身份,通常是用户的详细信息(如用户名)。getCredentials():返回用户的凭证(如密码),但通常不直接使用此方法。getAuthorities():返回用户的权限列表(角色或权限)。Spring Security 的授权机制用于控制用户对应用程序资源的访问权限。授权通常是基于用户角色或权限的,以下是对 Spring Security 授权的详细讲解。
GrantedAuthority 接口表示用户的权限。每个用户的权限可以通过实现该接口的对象来表示。Spring Security 支持多种授权方式,主要包括:
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/admin/**").hasRole("ADMIN") // 只有 ADMIN 角色可以访问。
.antMatchers("/user/**").hasAnyRole("USER", "ADMIN") // USER 和 ADMIN 角色可以访问。
.anyRequest().authenticated(); // 其他请求需要认证
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/edit/**").hasAuthority("EDIT_PRIVILEGE") // 仅具有 EDIT_PRIVILEGE 权限的用户可以访问。
.anyRequest().authenticated();
}
如果需要更复杂的授权逻辑,可以实现自定义的 AccessDecisionVoter 或 AccessDecisionManager。
AccessDecisionVoter 的调用,确定用户是否有权访问请求的资源。以下接口和类用于处理不同的安全事件,提供了自定义处理的能力:
AuthenticationSuccessHandler 接口,并重写 onAuthenticationSuccess 方法。public class MyAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
}
}
// 让我们实现的类生效
http.formLogin(form -> form.successHandler(new MyAuthenticationSuccessHandler()));
AuthenticationFailureHandler 接口,并重写 onAuthenticationFailure 方法。public class MyAuthenticationFailureHandler implements AuthenticationFailureHandler {
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
}
}
// 让我们实现的类生效
http.formLogin(form -> form.failureHandler(new MyAuthenticationFailureHandler()));
LogoutSuccessHandler 接口,并重写 onLogoutSuccess 方法。public class MyLogoutSuccessHandler implements LogoutSuccessHandler {
@Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
}
}
// 让我们实现的类生效
http.logout(logout -> {
logout.logoutSuccessHandler(new MyLogoutSuccessHandler());
});
AuthenticationEntryPoint 接口,并重写 commence 方法。// 重写 AuthenticationEntryPoint 接口
public class MyAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
}
}
// 让我们重写的类生效
http.exceptionHandling(exception -> {
exception.authenticationEntryPoint(new MyAuthenticationEntryPoint());
});
SessionInformationExpiredStrategy 接口,并重写 onExpiredSession 方法。// 重写 SessionInformationExpiredStrategy 接口
public class MySessionInformationExpiredStrategy implements SessionInformationExpiredStrategy {
@Override
public void onExpiredSessionDetected(SessionInformationExpiredEvent event) throws IOException, ServletException {
}
}
// 让我们重写的类生效
http.sessionManagement(session -> {
session.maximumSessions(1).expiredSessionStrategy(new MySessionInformationExpiredStrategy());
});
AccessDeniedHandler 接口的处理器。AccessDeniedHandler 接口,并重写 handle 方法。// 重写 AccessDeniedHandler 接口
public class MyAccessDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
}
}
// 在安全配置中注册自定义的 AccessDeniedHandler
http.exceptionHandling(exception -> {
exception.accessDeniedHandler(new MyAccessDeniedHandler());
});

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online