7
votes

I am writing a webservice with spring (this question is not about spring...) that implements a (hopefully) restful api. From my understanding all response should be in xml or json format. This is not really a big deal in most cases. But in one situation this seems not possible. I am using a facility from tomcat where a servlet is involved. I have to use a filter for some reason (and this reason is authentication). As I am new to servlets my understanding is eventually not so well, but to me it looks like this

My filter-class derives from javax.servlet.filter and I am writing my code within the doFilter method:

@Override
public void doFilter(ServletRequest request, ServletResponse response,
                          FilterChain chain) throws IOException, ServletException { // ... }

And at some point i realize i have to respond to the client with http status code 401 and also want to give him a xml or json information about what happened. Now to me it looks as if i can either

1) Use the ServletResponse: This allows me to get an OutputStream and write my xml/json out. However I cannot set the http status code at all. The final response arriving at the client does contain some http headers.

2) Cast ServletResponse to HttpServletResponse: This allows me to set status code, but I don't seem to be able to set the response body, but let response body be handled from tomcat.

Either way seems incomplete. If i use ServletResponse to write to the OutputStream and then cast to HttpServletResponse and then call sendError(401) - hoping that whatever I wrote to OutputStream reaches the client - my response does not contain an http "status line". However http headers are present like "Server: Apache-Coyote/1.1"

any help welcome...

3
Implementing REST in servlets is quite low level in my opinion. If possible I would try to use JAX-RS with Jersey for example, which is more convenient.simdevmon
I did not describe my situation to well... Please look at updated question. rest api is done with spring.Matthias

3 Answers

20
votes

I've implemented a filter for authentication shortly. I've coded something similar to this:

public void doFilter(ServletRequest req, ServletResponse resp,
                         FilterChain chain)
{
    HttpServletResponse response=(HttpServletResponse) resp;

    boolean authenticated=false;
    // perform authentication

    if (authenticated)
    {
         chain.doFilter(req, response);
    }
    else
    {
         // don't continue the chain
         response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
         response.setHeader("WWW-Authenticate", "BASIC realm=\"Your realm\"");

         response.setContentType("what you need");
         PrintWriter writer=response.getWriter();

         // don't set content length , don't close
    }
}
5
votes

This works for me:

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
    ServletException {

    response.resetBuffer();
    response.getOutputStream().write("Your content".getBytes());
    HttpServletResponse hsr = (HttpServletResponse) response;
    hsr.setStatus(401);
    chain.doFilter(request, response);
}
2
votes

Method HttpServletResponse::sendError is working for me to return from filter in SpringBoot 2.0 application:

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
if (authenticated)
    {
         chain.doFilter(req, response);
    }
    else
    {
    ((HttpServletResponse) response).sendError(HttpStatus.FORBIDDEN.value(), "Authorization shall be provided");
    }
    chain.doFilter(request, response);
}