如何在自定义Spring security 3.0身份验证中正确处理异常?

如何在自定义Spring security 3.0身份验证中正确处理异常?,spring,rest,spring-mvc,spring-security,Spring,Rest,Spring Mvc,Spring Security,我正在开发一个基于令牌的REST服务。当用户通过curl转到../rest/authenticate with the user and password时,获取一个有效令牌以使用整个API 当用户忘记在其他方法中插入用户名、密码或令牌时,就会出现我的问题,因为我没有按照自己的意愿处理身份验证异常 我可以处理异常,但是tomcat得到了响应并插入了一些我不期望的html 这是tomcat的典型响应。 有没有可能收到一个像200OK这样没有html代码的响应 现在,这是我的配置: Authen

我正在开发一个基于令牌的REST服务。当用户通过curl转到../rest/authenticate with the user and password时,获取一个有效令牌以使用整个API

当用户忘记在其他方法中插入用户名、密码或令牌时,就会出现我的问题,因为我没有按照自己的意愿处理身份验证异常

我可以处理异常,但是tomcat得到了响应并插入了一些我不期望的html

这是tomcat的典型响应。

有没有可能收到一个像200OK这样没有html代码的响应

现在,这是我的配置:

AuthenticationProcessingFilter 决定url是否安全。如果必须对其进行安全保护,请调用身份验证管理器对其进行验证。如果收到身份验证异常,则调用AuthenticationEntryPoint

public class AuthenticationTokenProcessingFilter extends GenericFilterBean {

    private final Collection<String> nonTokenAuthUrls = Lists.newArrayList("/rest","/rest/authenticate");

    TokenAuthenticationManager tokenAuthenticationManager;
    RestAuthenticationEntryPoint restAuthenticationEntryPoint;

    public AuthenticationTokenProcessingFilter(TokenAuthenticationManager tokenAuthenticationManager, RestAuthenticationEntryPoint restAuthenticationEntryPoint) {
        this.tokenAuthenticationManager = tokenAuthenticationManager;
        this.restAuthenticationEntryPoint = restAuthenticationEntryPoint;
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest)request;
        HttpServletResponse httpResponse = (HttpServletResponse)response;
        try{
            if(!nonTokenAuthUrls.contains(httpRequest.getRequestURI())){ //Auth by token
                 String hash = httpRequest.getHeader("token");
                 UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(hash, null);
                 authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails((HttpServletRequest) request));
                 SecurityContextHolder.getContext().setAuthentication(tokenAuthenticationManager.authenticate(authentication));
            }
            response.reset();
            chain.doFilter(request, response); 
        }catch(AuthenticationException authenticationException){
            SecurityContextHolder.clearContext();
            restAuthenticationEntryPoint.commence(httpRequest, httpResponse, authenticationException);
        }
    }
AuthenticationEntryPoint 这门课还可以。收到的代码是401未经授权的,但消息是在tomcat html中

公共类重新验证EntryPoint实现AuthenticationEntryPoint{

@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authenticationException) throws IOException, ServletException {
    response.setContentType("application/json");
    response.sendError( HttpServletResponse.SC_UNAUTHORIZED, authenticationException.getMessage() );
    response.getOutputStream().println("{ \"error\": \"" + authenticationException.getMessage() + "\" }");
}
}

RestAccessDeniedHanler也不被调用。这很困难,因为有很多类需要实现

我查看了stackoverflow和其他网站中的一些帖子,我的方法是在AuthenticationProcessingFilter中捕获异常并手动调用AuthenticationEntryPoint。我决定这样做是因为我试图在applicationContext-security.xml中配置它,但没有成功

appliacionContext-security.xml


如何发送带有错误代码和消息的清晰响应?

您可以使用web.xml中的错误页面截取Tomcat的错误页面。比如说,

<error-page>
    <error-code>404</error-code>
    <location>/404</location>
</error-page>

404
/404
现在,您可以使用RequestMapping将/404映射到一个页面,该页面返回您的JSON响应,而不包含任何HTML:

@RequestMapping(value = "/404", method = {RequestMethod.GET, RequestMethod.POST, RequestMethod.PUT, RequestMethod.DELETE})
@ResponseBody
public ResponseEntity<ResponseStatus> handle404() {

    HttpStatus status = null;
    ResponseStatus responseStatus = new ResponseStatus("404", "Wrong path to resource.");
    status = HttpStatus.NOT_FOUND;

    ResponseEntity<ResponseStatus> response = new ResponseEntity<ResponseStatus>(responseStatus, status);

    return response;
}
@RequestMapping(value=“/404”,method={RequestMethod.GET,RequestMethod.POST,RequestMethod.PUT,RequestMethod.DELETE})
@应答器
公共责任处理404(){
HttpStatus状态=空;
ResponseStatus ResponseStatus=新ResponseStatus(“404”,“资源路径错误”);
status=HttpStatus.NOT_FOUND;
ResponseEntity response=新的ResponseEntity(responseStatus,状态);
返回响应;
}

它只返回一个名为Response Status的JSON对象,其中包含一个错误代码和错误消息作为字段。

我没有提到在我的应用程序中有两个http。一个用于dp/rest,无需web浏览器即可访问;另一个用于dp/rest,具有要使用web浏览器访问的视图(jsp页面)。这只能通过web.xml实现吗?因为在web.xml中我已经有404/错误/notfound.jsp。。有可能分离错误吗?如果您知道异常是什么,您可以在Spring中定义ExceptionHandler,以便在抛出异常时执行任何您想要的操作。这听起来像你要找的。如果您需要更多信息,请告诉我。。。但一个开始寻找的好地方是:
<error-page>
    <error-code>404</error-code>
    <location>/404</location>
</error-page>
@RequestMapping(value = "/404", method = {RequestMethod.GET, RequestMethod.POST, RequestMethod.PUT, RequestMethod.DELETE})
@ResponseBody
public ResponseEntity<ResponseStatus> handle404() {

    HttpStatus status = null;
    ResponseStatus responseStatus = new ResponseStatus("404", "Wrong path to resource.");
    status = HttpStatus.NOT_FOUND;

    ResponseEntity<ResponseStatus> response = new ResponseEntity<ResponseStatus>(responseStatus, status);

    return response;
}