如何让Spring-Security以JSON格式返回401响应?
我有一个ReST API到一个应用程序,其中所有控制器都在下找到,这些都返回JSON响应,该响应处理所有异常以映射到JSON格式的结果。/api/
@ControllerAdvice
从春季4.0开始,这非常有效,现在支持在注释上进行匹配。我无法弄清楚的是如何返回401 - 未经身份验证和400 - 错误请求响应的JSON结果。@ControllerAdvice
相反,Spring只是将响应返回到容器(tomcat),该容器将其呈现为HTML。我如何拦截它并使用与我使用的相同技术呈现JSON结果。@ControllerAdvice
安全性.xml
<bean id="xBasicAuthenticationEntryPoint"
class="com.example.security.XBasicAuthenticationEntryPoint">
<property name="realmName" value="com.example.unite"/>
</bean>
<security:http pattern="/api/**"
create-session="never"
use-expressions="true">
<security:http-basic entry-point-ref="xBasicAuthenticationEntryPoint"/>
<security:session-management />
<security:intercept-url pattern="/api/**" access="isAuthenticated()"/>
</security:http>
XBasicAuthenticationEntryPoint
public class XBasicAuthenticationEntryPoint extends BasicAuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request,
HttpServletResponse response,
AuthenticationException authException)
throws IOException, ServletException {
HttpServletResponse httpResponse = (HttpServletResponse) response;
httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED,
authException.getMessage());
}
}
我可以通过使用 直接写入输出流来解决 401,但我不确定这是最好的方法。BasicAuthenticationEntryPoint
public class XBasicAuthenticationEntryPoint extends BasicAuthenticationEntryPoint {
private final ObjectMapper om;
@Autowired
public XBasicAuthenticationEntryPoint(ObjectMapper om) {
this.om = om;
}
@Override
public void commence(HttpServletRequest request,
HttpServletResponse response,
AuthenticationException authException)
throws IOException, ServletException {
HttpServletResponse httpResponse = (HttpServletResponse) response;
httpResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
om.writeValue(httpResponse.getOutputStream(),
new ApiError(request.getRequestURI(),
HttpStatus.SC_UNAUTHORIZED,
"You must sign in or provide basic authentication."));
}
}
我还没有弄清楚如何处理400,我曾经尝试过一个捕获所有控制器,它确实有效,但似乎有时它会与其他控制器有奇怪的冲突行为,我不想重新审视。
我的实现有一个陷阱,如果spring为错误请求(400)抛出任何异常,它应该在理论上捕获它,但它不会:ControllerAdvice
@ControllerAdvice(annotations = {RestController.class})
public class ApiControllerAdvisor {
@ExceptionHandler(Throwable.class)
public ResponseEntity<ApiError> exception(Throwable exception,
WebRequest request,
HttpServletRequest req) {
ApiError err = new ApiError(req.getRequestURI(), exception);
return new ResponseEntity<>(err, err.getStatus());
}
}