是否可以覆盖弹簧安全认证错误消息
Posted
技术标签:
【中文标题】是否可以覆盖弹簧安全认证错误消息【英文标题】:Is it possible to override the spring security authentication error message 【发布时间】:2020-11-06 23:51:14 【问题描述】:我们使用的是 Spring Boot 2.2.2。
当用户输入错误凭据时,我想在 json 响应中返回自定义错误消息以及 401 状态代码,因为我执行了以下步骤。
WebSecurityConfig.java:
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter
private final UserDetailsService userDetailsService;
private final RestAuthenticationEntryPoint restAuthenticationEntryPoint;
public WebSecurityConfig(RepositoryUserDetailsService userDetailsService RestAuthenticationEntryPoint restAuthenticationEntryPoint)
this.userDetailsService = userDetailsService;
this.restAuthenticationEntryPoint = restAuthenticationEntryPoint;
@Override
public void configure(final WebSecurity web)
web.ignoring()
.antMatchers(HttpMethod.OPTIONS, "/**")
.antMatchers("/proj-name/**/*.js,html")
.antMatchers("/test/**");
@Override
protected void configure(HttpSecurity http) throws Exception
http
.csrf()
.disable()
.exceptionHandling()
.authenticationEntryPoint(restAuthenticationEntryPoint)
.and()
.headers()
.frameOptions()
.disable()
.and()
.authorizeRequests()
.antMatchers(HttpMethod.GET, "/login").permitAll()
.antMatchers("/error").permitAll()
.anyRequest().authenticated()
.and()
.httpBasic();
@Bean
RestAuthenticationEntryPoint authenticationEntryPoint()
return new RestAuthenticationEntryPoint();
@Bean
AuthenticationEntryPoint forbiddenEntryPoint()
return new HttpStatusEntryPoint(FORBIDDEN);
@Bean
public CustomAuthenticationProvider customDaoAuthenticationProvider() throws Exception
CustomAuthenticationProvider customDaoAuthenticationProvider = new CustomAuthenticationProvider();
customDaoAuthenticationProvider.setPasswordEncoder(new PasswordEncoderConfig().encoder());
customDaoAuthenticationProvider.setUserDetailsService(userDetailsService);
return customDaoAuthenticationProvider;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception
auth.authenticationProvider(customDaoAuthenticationProvider());
RestAuthenticationEntryPoint.java
@Component
public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint
@Override
public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException
httpServletResponse.addHeader("WWW-Authenticate", "Basic realm=" + "");
httpServletResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
PrintWriter writer = httpServletResponse.getWriter();
writer.println("HTTP Status 401 - " + e.getMessage());
CustomAuthenticationProvider.java
public class CustomAuthenticationProvider extends DaoAuthenticationProvider
@Autowired
private PasswordEncoder passwordEncoder;
@Override
protected void additionalAuthenticationChecks(UserDetails userDetails,
UsernamePasswordAuthenticationToken authentication) throws AuthenticationException
if (authentication.getCredentials() == null)
logger.debug("Authentication failed: no credentials provided");
throw new BadCredentialsException(messages.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "test bad credentials"));
String presentedPassword = authentication.getCredentials().toString();
if (!passwordEncoder.matches(presentedPassword, userDetails.getPassword()))
throw new BadCredentialsException(
messages.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials","Invalid credentials"));
当我点击/login
api 时返回以下响应:Full authentication is required to access this resource
如果我添加 .antMatchers("/error").permitAll()
将返回以下响应。
"timestamp": 1594970514264,
"status": 401,
"error": "Unauthorized",
"message": "Unauthorized",
"path": "/login"
我尝试在 CustomAuthenticationProvider 上添加 @Component 注释,然后它在服务器启动时抛出以下错误:java.lang.IllegalArgumentException: A UserDetailsService must be set
我尝试按照url 添加CustomAuthenticationFailureHandler,但没有成功。我看过几篇文章,但这些例子也没有奏效。我还尝试使用 @ControllerAdvice 注释创建异常处理程序类,但仍然无效。是否有任何其他方法可以覆盖默认错误消息,或者我是否缺少任何注释或配置?提前感谢您的帮助!
【问题讨论】:
尝试将antMatchers(HttpMethod.GET, "/login").permitAll()
更改为antMatchers("/login").permitAll()
感谢您的建议。我试过它仍然返回"message": "Unauthorized",
。
【参考方案1】:
您可以使用控制器建议来处理服务引发的错误:
@ControllerAdvice
@Order(HIGHEST_PRECEDENCE)
public class AppointmentErrorController
@ExceptionHandler(BadCredentialsException.class)
public ResponseEntity<ApiError> handleError(HttpServletRequest request, BadCredentialsException ex)
ApiError apiError = new ApiError(...); //retrieve info from BadCredentialsException
return ResponseEntity.status(HttpStatus.UNAUTHORIZED, apiError);
【讨论】:
以上是关于是否可以覆盖弹簧安全认证错误消息的主要内容,如果未能解决你的问题,请参考以下文章
Grails:弹簧安全插件 - 错误 springsecurity.GormPersistentTokenRepository