org.springframework.security
spring-security-oauth2-authorization-server
diff --git a/youlai-auth/src/main/java/com/youlai/auth/authentication/captcha/CaptchaAuthenticationProvider.java b/youlai-auth/src/main/java/com/youlai/auth/authentication/captcha/CaptchaAuthenticationProvider.java
index b288c595c..3c12391a0 100644
--- a/youlai-auth/src/main/java/com/youlai/auth/authentication/captcha/CaptchaAuthenticationProvider.java
+++ b/youlai-auth/src/main/java/com/youlai/auth/authentication/captcha/CaptchaAuthenticationProvider.java
@@ -94,7 +94,7 @@ public class CaptchaAuthenticationProvider implements AuthenticationProvider {
String username = (String) additionalParameters.get(OAuth2ParameterNames.USERNAME);
String password = (String) additionalParameters.get(OAuth2ParameterNames.PASSWORD);
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(username, password);
- // 用户名密码身份验证,成功后返回带有权限的认证信息
+ // 用户名密码身份验证,成功后返回 带有权限的认证信息
Authentication usernamePasswordAuthentication = authenticationManager.authenticate(usernamePasswordAuthenticationToken);
// 访问令牌(Access Token) 构造器
@@ -119,6 +119,7 @@ public class CaptchaAuthenticationProvider implements AuthenticationProvider {
generatedAccessToken.getTokenValue(), generatedAccessToken.getIssuedAt(),
generatedAccessToken.getExpiresAt(), tokenContext.getAuthorizedScopes());
+
OAuth2Authorization.Builder authorizationBuilder = OAuth2Authorization.withRegisteredClient(registeredClient)
.principalName(usernamePasswordAuthentication.getName())
.authorizationGrantType(CaptchaAuthenticationToken.CAPTCHA)
diff --git a/youlai-auth/src/main/java/com/youlai/auth/authentication/wxminiapp/WxMiniAppAuthenticationConverter.java b/youlai-auth/src/main/java/com/youlai/auth/authentication/miniapp/WxMiniAppAuthenticationConverter.java
similarity index 98%
rename from youlai-auth/src/main/java/com/youlai/auth/authentication/wxminiapp/WxMiniAppAuthenticationConverter.java
rename to youlai-auth/src/main/java/com/youlai/auth/authentication/miniapp/WxMiniAppAuthenticationConverter.java
index 4b81f7864..1c924894e 100644
--- a/youlai-auth/src/main/java/com/youlai/auth/authentication/wxminiapp/WxMiniAppAuthenticationConverter.java
+++ b/youlai-auth/src/main/java/com/youlai/auth/authentication/miniapp/WxMiniAppAuthenticationConverter.java
@@ -1,4 +1,4 @@
-package com.youlai.auth.authentication.wxminiapp;
+package com.youlai.auth.authentication.miniapp;
import cn.hutool.core.util.StrUtil;
import com.youlai.auth.util.OAuth2EndpointUtils;
diff --git a/youlai-auth/src/main/java/com/youlai/auth/authentication/wxminiapp/WxMiniAppAuthenticationProvider.java b/youlai-auth/src/main/java/com/youlai/auth/authentication/miniapp/WxMiniAppAuthenticationProvider.java
similarity index 99%
rename from youlai-auth/src/main/java/com/youlai/auth/authentication/wxminiapp/WxMiniAppAuthenticationProvider.java
rename to youlai-auth/src/main/java/com/youlai/auth/authentication/miniapp/WxMiniAppAuthenticationProvider.java
index 9869ef3a9..f82624234 100644
--- a/youlai-auth/src/main/java/com/youlai/auth/authentication/wxminiapp/WxMiniAppAuthenticationProvider.java
+++ b/youlai-auth/src/main/java/com/youlai/auth/authentication/miniapp/WxMiniAppAuthenticationProvider.java
@@ -1,4 +1,4 @@
-package com.youlai.auth.authentication.wxminiapp;
+package com.youlai.auth.authentication.miniapp;
import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
diff --git a/youlai-auth/src/main/java/com/youlai/auth/authentication/wxminiapp/WxMiniAppAuthenticationToken.java b/youlai-auth/src/main/java/com/youlai/auth/authentication/miniapp/WxMiniAppAuthenticationToken.java
similarity index 97%
rename from youlai-auth/src/main/java/com/youlai/auth/authentication/wxminiapp/WxMiniAppAuthenticationToken.java
rename to youlai-auth/src/main/java/com/youlai/auth/authentication/miniapp/WxMiniAppAuthenticationToken.java
index 6977301c4..edcfd3b2b 100644
--- a/youlai-auth/src/main/java/com/youlai/auth/authentication/wxminiapp/WxMiniAppAuthenticationToken.java
+++ b/youlai-auth/src/main/java/com/youlai/auth/authentication/miniapp/WxMiniAppAuthenticationToken.java
@@ -1,4 +1,4 @@
-package com.youlai.auth.authentication.wxminiapp;
+package com.youlai.auth.authentication.miniapp;
import jakarta.annotation.Nullable;
import org.springframework.security.core.Authentication;
diff --git a/youlai-auth/src/main/java/com/youlai/auth/authentication/password/PasswordAuthenticationConverter.java b/youlai-auth/src/main/java/com/youlai/auth/authentication/password/PasswordAuthenticationConverter.java
index 7acf99857..c555eaa11 100644
--- a/youlai-auth/src/main/java/com/youlai/auth/authentication/password/PasswordAuthenticationConverter.java
+++ b/youlai-auth/src/main/java/com/youlai/auth/authentication/password/PasswordAuthenticationConverter.java
@@ -2,6 +2,7 @@ package com.youlai.auth.authentication.password;
import cn.hutool.core.util.StrUtil;
import com.youlai.auth.util.OAuth2EndpointUtils;
+import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.core.AuthorizationGrantType;
@@ -32,6 +33,7 @@ public class PasswordAuthenticationConverter implements AuthenticationConverter
@Override
public Authentication convert(HttpServletRequest request) {
+
// 授权类型 (必需)
String grantType = request.getParameter(OAuth2ParameterNames.GRANT_TYPE);
if (!AuthorizationGrantType.PASSWORD.getValue().equals(grantType)) {
diff --git a/youlai-auth/src/main/java/com/youlai/auth/authentication/password/PasswordAuthenticationProvider.java b/youlai-auth/src/main/java/com/youlai/auth/authentication/password/PasswordAuthenticationProvider.java
index f1c7f57e7..c7b99700d 100644
--- a/youlai-auth/src/main/java/com/youlai/auth/authentication/password/PasswordAuthenticationProvider.java
+++ b/youlai-auth/src/main/java/com/youlai/auth/authentication/password/PasswordAuthenticationProvider.java
@@ -2,13 +2,15 @@ package com.youlai.auth.authentication.password;
import cn.hutool.core.lang.Assert;
+import cn.hutool.core.util.ReflectUtil;
import com.youlai.auth.util.OAuth2AuthenticationProviderUtils;
import lombok.extern.slf4j.Slf4j;
-import org.springframework.security.authentication.AuthenticationManager;
-import org.springframework.security.authentication.AuthenticationProvider;
-import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.authentication.*;
+import org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UserDetailsChecker;
import org.springframework.security.oauth2.core.*;
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
import org.springframework.security.oauth2.core.oidc.OidcIdToken;
@@ -35,7 +37,6 @@ import java.util.stream.Collectors;
* 密码模式身份验证提供者
*
* 处理基于用户名和密码的身份验证
- *
* @author haoxr
* @since 3.0.0
*/
@@ -86,7 +87,12 @@ public class PasswordAuthenticationProvider implements AuthenticationProvider {
Map additionalParameters = resourceOwnerPasswordAuthentication.getAdditionalParameters();
String username = (String) additionalParameters.get(OAuth2ParameterNames.USERNAME);
String password = (String) additionalParameters.get(OAuth2ParameterNames.PASSWORD);
- UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(username, password);
+
+ // 这种
+ // https://github.com/Basit-Mahmood/spring-authorization-server-password-grant-type-support/blob/master/SpringAuthorizationServer/src/main/java/pk/training/basit/oauth2/authentication/OAuth2ResourceOwnerPasswordAuthenticationProvider.java
+ UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(username, password);
+
+
// 用户名密码身份验证,成功后返回带有权限的认证信息
Authentication usernamePasswordAuthentication = authenticationManager.authenticate(usernamePasswordAuthenticationToken);
@@ -126,11 +132,15 @@ public class PasswordAuthenticationProvider implements AuthenticationProvider {
generatedAccessToken.getTokenValue(), generatedAccessToken.getIssuedAt(),
generatedAccessToken.getExpiresAt(), tokenContext.getAuthorizedScopes());
+
+ ReflectUtil.setFieldValue(usernamePasswordAuthentication.getPrincipal(), "perms", null);
+
+ // 持久化令牌发放记录到数据库
OAuth2Authorization.Builder authorizationBuilder = OAuth2Authorization.withRegisteredClient(registeredClient)
.principalName(usernamePasswordAuthentication.getName())
.authorizationGrantType(AuthorizationGrantType.PASSWORD)
.authorizedScopes(authorizedScopes)
- .attribute(Principal.class.getName(), usernamePasswordAuthentication);
+ .attribute(Principal.class.getName(), usernamePasswordAuthentication); // attribute 字段
if (generatedAccessToken instanceof ClaimAccessor) {
authorizationBuilder.token(accessToken, (metadata) ->
metadata.put(OAuth2Authorization.Token.CLAIMS_METADATA_NAME, ((ClaimAccessor) generatedAccessToken).getClaims()));
@@ -197,4 +207,6 @@ public class PasswordAuthenticationProvider implements AuthenticationProvider {
return PasswordAuthenticationToken.class.isAssignableFrom(authentication);
}
+
+
}
diff --git a/youlai-auth/src/main/java/com/youlai/auth/config/AuthorizationServerConfig.java b/youlai-auth/src/main/java/com/youlai/auth/config/AuthorizationServerConfig.java
index ee67691f9..f6be85366 100644
--- a/youlai-auth/src/main/java/com/youlai/auth/config/AuthorizationServerConfig.java
+++ b/youlai-auth/src/main/java/com/youlai/auth/config/AuthorizationServerConfig.java
@@ -2,6 +2,8 @@
package com.youlai.auth.config;
import cn.binarywang.wx.miniapp.api.WxMaService;
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.convert.Convert;
import com.fasterxml.jackson.databind.Module;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.nimbusds.jose.jwk.JWKSet;
@@ -17,14 +19,16 @@ import com.youlai.auth.authentication.password.PasswordAuthenticationProvider;
import com.youlai.auth.authentication.smscode.SmsCodeAuthenticationConverter;
import com.youlai.auth.authentication.smscode.SmsCodeAuthenticationProvider;
import com.youlai.auth.authentication.smscode.SmsCodeAuthenticationToken;
-import com.youlai.auth.authentication.wxminiapp.WxMiniAppAuthenticationConverter;
-import com.youlai.auth.authentication.wxminiapp.WxMiniAppAuthenticationProvider;
-import com.youlai.auth.authentication.wxminiapp.WxMiniAppAuthenticationToken;
+import com.youlai.auth.authentication.miniapp.WxMiniAppAuthenticationConverter;
+import com.youlai.auth.authentication.miniapp.WxMiniAppAuthenticationProvider;
+import com.youlai.auth.authentication.miniapp.WxMiniAppAuthenticationToken;
+import com.youlai.auth.handler.MyAuthenticationFailureHandler;
import com.youlai.auth.handler.MyAuthenticationSuccessHandler;
import com.youlai.auth.userdetails.member.MemberDetailsService;
import com.youlai.auth.userdetails.user.SysUserDetails;
-import com.youlai.auth.userdetails.user.jackson.SysUseMixin;
+import com.youlai.auth.userdetails.user.jackson.SysUserMixin;
import lombok.RequiredArgsConstructor;
+import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -34,8 +38,10 @@ import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.support.lob.DefaultLobHandler;
import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.jackson2.SecurityJackson2Modules;
@@ -98,22 +104,23 @@ public class AuthorizationServerConfig {
) throws Exception {
- OAuth2AuthorizationServerConfigurer authorizationServerConfigurer =
- new OAuth2AuthorizationServerConfigurer();
+ OAuth2AuthorizationServerConfigurer authorizationServerConfigurer = new OAuth2AuthorizationServerConfigurer();
+
authorizationServerConfigurer
.tokenEndpoint(tokenEndpoint ->
tokenEndpoint
- .accessTokenRequestConverters(authenticationConverters ->// <1>
- authenticationConverters.addAll(
- List.of(
- new PasswordAuthenticationConverter(),
- new CaptchaAuthenticationConverter(),
- new WxMiniAppAuthenticationConverter(),
- new SmsCodeAuthenticationConverter()
+ .accessTokenRequestConverters(
+ authenticationConverters ->// <1>
+ authenticationConverters.addAll(
+ List.of(
+ new PasswordAuthenticationConverter(),
+ new CaptchaAuthenticationConverter(),
+ new WxMiniAppAuthenticationConverter(),
+ new SmsCodeAuthenticationConverter()
+ )
)
- )
)
- .authenticationProviders(authenticationProviders ->// <2>
+ /*.authenticationProviders(authenticationProviders ->// <2>
authenticationProviders.addAll(
List.of(
new PasswordAuthenticationProvider(authenticationManager, authorizationService, tokenGenerator),
@@ -122,25 +129,37 @@ public class AuthorizationServerConfig {
new SmsCodeAuthenticationProvider(authorizationService, tokenGenerator, memberDetailsService, redisTemplate)
)
)
- )
- .accessTokenResponseHandler(new MyAuthenticationSuccessHandler())
+ )*/
+ .accessTokenResponseHandler(new MyAuthenticationSuccessHandler()) // 自定义成功响应
+ .errorResponseHandler(new MyAuthenticationFailureHandler()) // 自定义异常响应
);
- RequestMatcher endpointsMatcher = authorizationServerConfigurer.getEndpointsMatcher();
- http
- .securityMatcher(endpointsMatcher)
- .authorizeHttpRequests(authorize ->
- authorize
- .anyRequest().authenticated()
- )
+ RequestMatcher endpointsMatcher = authorizationServerConfigurer.getEndpointsMatcher();
+ http.securityMatcher(endpointsMatcher)
+ .authorizeHttpRequests(authorizeRequests -> authorizeRequests.anyRequest().authenticated())
.csrf(csrf -> csrf.ignoringRequestMatchers(endpointsMatcher))
.apply(authorizationServerConfigurer);
+
+ AuthenticationManagerBuilder authenticationManagerBuilder = http.getSharedObject(AuthenticationManagerBuilder.class);
+ authenticationManagerBuilder.parentAuthenticationManager(null);
+ authenticationManagerBuilder.authenticationProvider(new PasswordAuthenticationProvider(authenticationManager, authorizationService, tokenGenerator));
+
+
return http.build();
}
+ /* @Bean
+ public AuthenticationProvider daoAuthenticationProvider() {
+ DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
+ daoAuthenticationProvider.setUserDetailsService(userDetailsService);
+ daoAuthenticationProvider.setHideUserNotFoundExceptions(false) ; // 抛出用户不存在异常
+ return daoAuthenticationProvider ;
+ }*/
+
+
@Bean // <5>
public JWKSource jwkSource() {
KeyPair keyPair = generateRsaKey();
@@ -208,7 +227,7 @@ public class AuthorizationServerConfig {
objectMapper.registerModules(securityModules);
objectMapper.registerModule(new OAuth2AuthorizationServerJackson2Module());
// You will need to write the Mixin for your class so Jackson can marshall it.
- objectMapper.addMixIn(SysUserDetails.class, SysUseMixin.class);
+ objectMapper.addMixIn(SysUserDetails.class, SysUserMixin.class);
objectMapper.addMixIn(Long.class, Object.class);
rowMapper.setObjectMapper(objectMapper);
service.setAuthorizationRowMapper(rowMapper);
@@ -236,11 +255,9 @@ public class AuthorizationServerConfig {
}
-
-
-
@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
+
return authenticationConfiguration.getAuthenticationManager();
}
diff --git a/youlai-auth/src/main/java/com/youlai/auth/config/SecurityConfig.java b/youlai-auth/src/main/java/com/youlai/auth/config/DefaultSecurityConfig.java
similarity index 85%
rename from youlai-auth/src/main/java/com/youlai/auth/config/SecurityConfig.java
rename to youlai-auth/src/main/java/com/youlai/auth/config/DefaultSecurityConfig.java
index 7800bbdf9..c7e34f790 100644
--- a/youlai-auth/src/main/java/com/youlai/auth/config/SecurityConfig.java
+++ b/youlai-auth/src/main/java/com/youlai/auth/config/DefaultSecurityConfig.java
@@ -6,26 +6,22 @@ import lombok.RequiredArgsConstructor;
import lombok.Setter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
+import org.springframework.core.annotation.Order;
+import org.springframework.security.config.Customizer;
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.WebSecurityCustomizer;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
-import org.springframework.security.crypto.factory.PasswordEncoderFactories;
-import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import java.util.List;
-import static org.springframework.security.config.Customizer.withDefaults;
-
-@Configuration
-@EnableWebSecurity(debug = true)
-@RequiredArgsConstructor
-public class SecurityConfig {
+@EnableWebSecurity
+@Configuration(proxyBeanMethods = false)
+public class DefaultSecurityConfig {
@Setter
private List ignoreUrls;
-
/**
* Spring Security 安全过滤器链配置
*
@@ -33,6 +29,7 @@ public class SecurityConfig {
* @return
*/
@Bean
+ @Order(0)
SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(requestMatcherRegistry ->
@@ -45,8 +42,8 @@ public class SecurityConfig {
}
)
.csrf(AbstractHttpConfigurer::disable)
- .formLogin(withDefaults())
- ;
+ .formLogin(Customizer.withDefaults());
+
return http.build();
}
diff --git a/youlai-auth/src/main/java/com/youlai/auth/config/JwtCustomizerConfig.java b/youlai-auth/src/main/java/com/youlai/auth/config/JwtTokenClaimsConfig.java
similarity index 92%
rename from youlai-auth/src/main/java/com/youlai/auth/config/JwtCustomizerConfig.java
rename to youlai-auth/src/main/java/com/youlai/auth/config/JwtTokenClaimsConfig.java
index bcf85d11a..505325996 100644
--- a/youlai-auth/src/main/java/com/youlai/auth/config/JwtCustomizerConfig.java
+++ b/youlai-auth/src/main/java/com/youlai/auth/config/JwtTokenClaimsConfig.java
@@ -8,7 +8,6 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
-import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.oauth2.core.oidc.endpoint.OidcParameterNames;
@@ -17,7 +16,6 @@ import org.springframework.security.oauth2.server.authorization.OAuth2TokenType;
import org.springframework.security.oauth2.server.authorization.token.JwtEncodingContext;
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenCustomizer;
-import java.util.Collection;
import java.util.Collections;
import java.util.Optional;
import java.util.Set;
@@ -27,16 +25,17 @@ import java.util.stream.Collectors;
* 自定义 JWT 的 Claims(声明)
*
* @author haoxr
+ * @see How-to: Authorize an access token containing custom authorities
* @since 2023/7/4
*/
@Configuration
@RequiredArgsConstructor
-public class JwtCustomizerConfig {
+public class JwtTokenClaimsConfig {
private final RedisTemplate redisTemplate;
@Bean
- public OAuth2TokenCustomizer jwtCustomizer() {
+ public OAuth2TokenCustomizer jwtTokenCustomizer() {
return context -> {
if (OAuth2TokenType.ACCESS_TOKEN.equals(context.getTokenType()) && context.getPrincipal() instanceof UsernamePasswordAuthenticationToken) {
// Customize headers/claims for access_token
@@ -59,7 +58,7 @@ public class JwtCustomizerConfig {
} else if (principal instanceof MemberDetails userDetails) {
claims.claim("member_id", String.valueOf(userDetails.getId()));
- }else{
+ } else {
User user = (User) principal;
// 这里存入角色至JWT,解析JWT的角色用于鉴权的位置: ResourceServerConfig#jwtAuthenticationConverter
diff --git a/youlai-auth/src/main/java/com/youlai/auth/controller/AuthController.java b/youlai-auth/src/main/java/com/youlai/auth/controller/AuthController.java
index a6412a5cd..3fc0c37fe 100644
--- a/youlai-auth/src/main/java/com/youlai/auth/controller/AuthController.java
+++ b/youlai-auth/src/main/java/com/youlai/auth/controller/AuthController.java
@@ -3,6 +3,8 @@ package com.youlai.auth.controller;
import org.springframework.web.bind.annotation.RestController;
/**
+ * 认证控制器
+ *
* @author haoxr
* @since 2023/6/29
*/
diff --git a/youlai-auth/src/main/java/com/youlai/auth/handler/MyAuthenticationFailureHandler.java b/youlai-auth/src/main/java/com/youlai/auth/handler/MyAuthenticationFailureHandler.java
new file mode 100644
index 000000000..6f772dfcb
--- /dev/null
+++ b/youlai-auth/src/main/java/com/youlai/auth/handler/MyAuthenticationFailureHandler.java
@@ -0,0 +1,42 @@
+package com.youlai.auth.handler;
+
+import com.youlai.common.result.Result;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.converter.HttpMessageConverter;
+import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
+import org.springframework.http.server.ServletServerHttpResponse;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
+import org.springframework.security.oauth2.core.OAuth2Error;
+import org.springframework.security.web.authentication.AuthenticationFailureHandler;
+import org.springframework.stereotype.Component;
+
+import java.io.IOException;
+
+/**
+ * 认证异常处理器
+ *
+ * @author haoxr
+ * @since 2023/7/6
+ */
+@Slf4j
+public class MyAuthenticationFailureHandler implements AuthenticationFailureHandler {
+
+ private final HttpMessageConverter