Bre*_*yan 25 java spring-mvc spring-security
我有一个ReST API到一个应用程序,其中找到了所有控制器/api/
,这些都返回JSON响应,@ControllerAdvice
其中处理所有异常以映射到JSON格式的结果.
这在春季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>
Run Code Online (Sandbox Code Playgroud)
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());
}
}
Run Code Online (Sandbox Code Playgroud)
我可以通过使用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."));
}
}
Run Code Online (Sandbox Code Playgroud)
我还没弄明白如何处理400,我曾经试过捕捉所有控制器做了工作,但似乎有时它会与其他控制器有奇怪的冲突行为,我不想重新审视.
我的ControllerAdvice
实现有一个捕获所有如果spring抛出任何异常的错误请求(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());
}
}
Run Code Online (Sandbox Code Playgroud)
rhi*_*nds 17
几周前我发现自己问了同样的问题 - 正如Dirk在评论中指出的那样,@ ControllerAdvice只会在控制器方法中抛出异常时启动,所以不可避免地会抓住所有东西(我实际上是试图解决404错误的JSON响应的情况).
我确定的解决方案,虽然不是很愉快(希望如果你得到一个更好的答案,我将改变我的方法)是在Web.xml中处理错误映射 - 我添加了以下内容,它将覆盖特定于tomcat的默认错误页面URL映射:
<error-page>
<error-code>404</error-code>
<location>/errors/resourcenotfound</location>
</error-page>
<error-page>
<error-code>403</error-code>
<location>/errors/unauthorised</location>
</error-page>
<error-page>
<error-code>401</error-code>
<location>/errors/unauthorised</location>
</error-page>
Run Code Online (Sandbox Code Playgroud)
现在,如果任何页面返回404,它由我的错误控制器处理,如下所示:
@Controller
@RequestMapping("/errors")
public class ApplicationExceptionHandler {
@ResponseStatus(HttpStatus.NOT_FOUND)
@RequestMapping("resourcenotfound")
@ResponseBody
public JsonResponse resourceNotFound(HttpServletRequest request, Device device) throws Exception {
return new JsonResponse("ERROR", 404, "Resource Not Found");
}
@ResponseStatus(HttpStatus.UNAUTHORIZED)
@RequestMapping("unauthorised")
@ResponseBody
public JsonResponse unAuthorised(HttpServletRequest request, Device device) throws Exception {
return new JsonResponse("ERROR", 401, "Unauthorised Request");
}
}
Run Code Online (Sandbox Code Playgroud)
这一切仍然感觉非常严峻 - 当然是全局处理错误 - 所以如果你不总是希望404响应是json(如果你正在服务同一个应用程序的正常webapp)那么它不能很好地工作.但就像我说的那样,我决定采取行动,这里希望有一个更好的方式!
您应该注意在 ResponseEntity 中设置错误代码,如下所示:
new ResponseEntity<String>(err, HttpStatus.UNAUTHORIZED);
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
26615 次 |
最近记录: |