Redirecting a web client from a servlet-filter (cl

2020-06-29 02:58发布

问题:

I'm doing a web with JAASRealm authentication (in tomcat 7). This is a filter for the servlets:

private String loginPage = "welcome.jsp";

@Override
public void doFilter(ServletRequest request, ServletResponse response,
        FilterChain filterChain) throws IOException, ServletException {

    if ((request instanceof HttpServletRequest) && (response instanceof HttpServletResponse)) {
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        HttpServletResponse httpServletResponse = (HttpServletResponse) response;
        if (httpServletRequest.getUserPrincipal() == null) {
            // User is not logged in, redirect to login page.
            httpServletRequest.setAttribute("from", httpServletRequest.getRequestURI());
            httpServletResponse.sendRedirect(loginPage);
        }
        else {
            filterChain.doFilter(request, response);
        }
    }
}

And I have declared it in web.xml

<filter>
    <filter-name>login-filter</filter-name>
    <filter-class>LoginFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>login-filter</filter-name>
    <url-pattern>/sampleServlet</url-pattern>
</filter-mapping>

My problem is when I'm not authenticated and I call the servlet via AJAX, this line of filter doesn't work

httpServletResponse.sendRedirect(loginPage);

So, I haven't receive any data and I'm not redirected to the loggin page. What can I do in this case?

回答1:

Here is how I send re-directs when Filtering AJAX requests...

AJAX Code (jQuery)

$.ajax({
    type: 'post',
    url: '/signMeInServlet',
    data: {
        'name': name,
        'pass': passW,
        },
    dataType: 'json',
    success: processSignInReturnMethod,
    error: function (xhr, ajaxOptions, thrownError){
        if (thrownError.redirect.length) {
            window.location.replace(thrownError.redirect);
        } else {
            alert('There was an error processing your request, please try again');
        }
    }
});

Relevant Filter Code

// Rest of your Filter processing and logic here, once you know you want
// to redirect, use the below code, which works for both AJAX and regualar
// requests

HttpServletRequest hreq = (HttpServletRequest) request;
String redirectUrl = "/redirected.jsp";

if (hreq.getHeader("x-requested-with") != null && 
        hreq.getHeader("x-requested-with").equalsIgnoreCase("XMLHttpRequest")) {

    // Set up your response here
    HttpServletResponse hres = (HttpServletResponse) response;
    hres.setContentType("text/json; charset=UTF-8");

    PrintWriter out = hres.getWriter();

    String json = "[{\"redirect\":\"" + redirectUrl + "\"}]";

    out.write(json);
    out.flush();
    out.close();

} else {

    ((HttpServletResponse)response).sendRedirect(redirectUrl);
}


回答2:

I tried to use some elegant solution, but none worked. I found this one ate primefaces forum, and worked also on a pure JSF application.

I used a Web Filter:

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    HttpServletRequest httpRequest = (HttpServletRequest) request;
    HttpServletResponse httpResponse = (HttpServletResponse) response;

    if(!identity.isLoggedIn()){
        if (isAjax(httpRequest)) {
            httpResponse.getWriter().print(xmlPartialRedirectToPage(httpRequest, "/login.xhtml"));
            httpResponse.flushBuffer();                
        }else{
            httpResponse.sendRedirect(httpRequest.getContextPath() + "/login.xhtml");
        }
    }else{
        chain.doFilter(request, response);
    }
}

private String xmlPartialRedirectToPage(HttpServletRequest request, String page) {
    StringBuilder sb = new StringBuilder();
    sb.append("<?xml version='1.0' encoding='UTF-8'?>");
    sb.append("<partial-response><redirect url=\"").append(request.getContextPath()).append(request.getServletPath()).append(page).append("\"/></partial-response>");
    return sb.toString();
}

private boolean isAjax(HttpServletRequest request) {
    return "XMLHttpRequest".equals(request.getHeader("X-Requested-With"));
}


回答3:

I solved the problem but not as I would. I use in the servler-filter this line

httpServletResponse.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY);

and in the client, using the ajax request I capture this status and then I do the redirect

var fAjaxRedirect = function(response, textStatus) {
    /* 301 is the code SC_MOVED_PERMANENTLY */
    if (response.status == 301) {
        location.reload(); //or location.href = 'xxxx.jsp';
 }};

    $.ajaxSetup({
        scriptCharset: "utf-8", 
        contentType: "application/x-www-form-urlencoded; charset=UTF-8"
    });
    $.ajax({
      type: "POST",
      url: "myServlet",
      complete: fAjaxRedirect,
      success: function(val) { 
          //something here
      }
    });

But doing it using that way, is the client who does the redirect of a page, and I would like to do it from the server, not depending the client.