今天发现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);
}
@Override
protected 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();
}
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
inner(request, response, authException, "errors.auth.noAuth");
}
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
inner(request, response, accessDeniedException, "errors.auth.dataNotPermitted");
}
}
对应多语言:
运行了一下,发现正常了
已经成为我需要的错误返回格式了