今天发现spring的异常格式没有跟着mvc的错误格式走,场景是用户权限的时候。查了一下原来是springsecurity定义了一组filter作用在了mvc上层,因此需要处理一下错误格式。
处理前错误返回信息如下:
由于使用了多语言,因此错误格式也要跟着多语言走,稍微绕了点弯。配置定义如下:
@Configuration
@AutoConfigureBefore({com.xkcoding.justauth.autoconfigure.JustAuthAutoConfiguration.class})
@EnableWebSecurity
public class SecurityConfigurer extends WebSecurityConfigurerAdapter {private RedissonClient redissonClient;private SecurityExceptionHandler securityExceptionHandler;public SecurityConfigurer(RedissonClient redissonClient, MessageSource messageSource, LocaleResolver localeResolver) {this.redissonClient = redissonClient;this.securityExceptionHandler = new SecurityExceptionHandler(messageSource, localeResolver);}@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().antMatchers("/"+GlobalEx.ADMIN_URI_PERFIX+"/**").authenticated().antMatchers("/"+GlobalEx.API_URI_PERFIX+"/**").authenticated().and().addFilterAfter(new JwtHeadFilter(redissonClient), UsernamePasswordAuthenticationFilter.class).sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().exceptionHandling().authenticationEntryPoint(securityExceptionHandler).accessDeniedHandler(securityExceptionHandler).and().csrf().disable();}
}
主要是
.and().exceptionHandling().authenticationEntryPoint(securityExceptionHandler).accessDeniedHandler(securityExceptionHandler)
这一段,定义了权限解析失败以及没有权限时的错误异常
需要对应的interface处理,看了下两个的格式比较接近,逻辑代码也接近,索性一个类处理了这两种解析:
package org.ccframe.commons.auth;import com.alibaba.fastjson.JSON;
import lombok.extern.log4j.Log4j2;
import org.ccframe.subsys.core.dto.Result;
import org.springframework.context.MessageSource;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.web.servlet.LocaleResolver;import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Locale;@Log4j2
public class SecurityExceptionHandler implements AccessDeniedHandler, AuthenticationEntryPoint{private final Object[] EMPTY_ARGS = new Object[0];private final LocaleResolver localeResolver;private final MessageSource messageSource;public SecurityExceptionHandler(MessageSource messageSource, LocaleResolver localeResolver){this.messageSource = messageSource;this.localeResolver = localeResolver;}private void inner(HttpServletRequest request, HttpServletResponse response, RuntimeException exception, String msgKey) throws IOException {Locale currentLocale = localeResolver.resolveLocale(request);String message = "";message = messageSource.getMessage(msgKey, EMPTY_ARGS, currentLocale); // 未登陆/无权限log.error(message, exception);response.setStatus(HttpServletResponse.SC_FORBIDDEN);response.setHeader("Content-Type","application/json;charset=utf-8");PrintWriter writer = response.getWriter() ;writer.write(JSON.toJSONString(Result.error(HttpServletResponse.SC_FORBIDDEN, message, exception.getClass().getName())));writer.flush();writer.close();}@Overridepublic void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {inner(request, response, authException, "errors.auth.noAuth");}@Overridepublic void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {inner(request, response, accessDeniedException, "errors.auth.dataNotPermitted");}}
对应多语言:
运行了一下,发现正常了
已经成为我需要的错误返回格式了