我有一个应用程序的ReST API,所有控制器在/api/
下找到,这些都返回JSON响应与@ControllerAdvice
处理所有异常映射到JSON格式的结果。如何让Spring-Security以JSON格式返回401响应?
此功能在春季4.0时效果很好@ControllerAdvice
现在支持在注释上进行匹配。我无法解决的是如何为401返回JSON结果 - 未认证和400 - 错误请求响应。
取而代之的是,Spring只是简单地将容器(tomcat)的响应返回给HTML。我如何拦截这个并使用我的@ControllerAdvice
正在使用的相同技术来呈现JSON结果。
的security.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());
}
}
我可以通过使用BasicAuthenticationEntryPoint
直接写入到输出流解决401,但我不知道它的最好的方法。
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虽然,我曾经试图包罗万象的控制器,它没有工作,但它似乎有时它会奇怪冲突的行为与我不希望其他控制器重新审视。
我ControllerAdvice
实现有一个捕获所有这些仿佛春天抛出任何异常的不良请求(400),它在理论上应该抓住它,但它并不:
@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());
}
}
对于401你的解决方案似乎是合适的:如果它是一个未经验证的请求,它永远不会打你的控制器,所以建议是没有帮助的。对于400我认为这取决于。如果因为控制器中没有匹配的签名而被返回,我很不确定这个通知是否会启动(显然不是)。 –
谢谢德克,只是不完全确定'400',它确实工作正常。对于'400',我已经测试了映射期望的请求参数的位置,如果省略了参数,我会得到普通的'HTML'响应。它实际上是有意义的思考它,因为控制器方法不会被调用,这是春季之前发现的故障,因此再次不会像401用户那样调用顾问。 –