从 Java Servlet 向 Web API 发送获取请求

To send get request to Web API from Java Servlet

常见问题

是否可以从 Java servlet 的 doGet 方法发送 get reguest?我需要根据我的 Web API .NET 服务检查一些 "ticket",所以我可以在 doGet 方法中从我的自定义 servlet 调用此服务吗?

public class IdentityProviderServlet extends HttpServlet {
...
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
...
// make request to Web API and save received user name to response
...
}

详情

我们有使用 TIBCO Spotfire 7.0 作为分析报告引擎的网络应用程序(.NET、MVC5)。 为了让我们的用户在网络应用程序中查看报告,我们使用 Spotfire WebPlayer(IIS 网络应用程序)和 JavaScript API。我们在 Web 应用程序中对我们的用户进行身份验证,然后允许他们利用 JS API 获得对 WebPlayer 的请求。为了使用已经过身份验证的用户,我们在 WebPlayer 上实现了基于密钥票证的自定义身份验证,如 here 所述。因此,我们创建了由 Spotfire WebPlayer 加载并调用重写函数的 .NET 程序集。在此函数中,我们调用 Web API 服务来验证用户并获取有效的 spotfire 用户名,然后我使用收到的用户名创建 IIdentity。 当新版本的 TIBCO Spotfire 7.5 发布时,我们发现它们 removed support of custom authentication, because they changed architecture and now they support "external authentication”。这种方法可以实现为 Java servlet,用于验证用户然后 spotfire:

Retrieves the user name from the getUserPrincipal() method of javax.servlet.http.HttpServletRequest

所有这些都迫使我们重新编写 Java 中的逻辑。然而,我们不想改变我们身份验证的整体工作流程,我们想坚持已经工作的票务模式。我是 Java servlet 的新手,所以我的目标是基于 servlet 实现相同的身份验证。他们有 example where servlet class has methods doGet and doPost (link to zip with example)。我在这里的假设是我可以实现自己的 doGet 并将请求发送到 Web API 以验证票证并取回用户名。

有意义吗?

您可以使用图书馆 Apache HTTP Components

doGet() 的简短示例(我没有编译它):

import org.apache.http.*;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.*;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.InputStreamEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;

protected void doGet(HttpServletRequest req, HttpServletResponse resp)
{
   String url="http://your.server.com/path/to/app?par1=yxc&par2=abc");
   HttpGet get=new HttpGet(url);
   httpClient = HttpClients.createDefault();
   // optional configuration
   RequestConfig config=RequestConfig.custom().setSocketTimeout(socketTimeoutSec * 1000).build();
    // more configuration

    get.setConfig(config);

    CloseableHttpResponse internResponse = httpClient.execute(get);

    int internResponseStatus = internResponse.getStatusLine().getStatusCode();

    InputStream respIn = internResponseEntity.getContent();
    String contentType = internResponseEntity.getContentType().getValue();

    // consume the response
}

最后我得到了这段代码。我实现了简单的过滤器而不是 servlet。

import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.HttpClients;
import java.io.*;
import org.json.*;

public class Authenticator implements IAuthenticator {

    @Override
    public IIdentity doAuthentication(String pathToAuthIdentity) throws IOException {
        try {
            // Create an instance of HttpClient.
            HttpClient httpClient = HttpClients.createDefault();

            // Create a method instance.
            HttpGet get = new HttpGet(pathToAuthIdentity);

            HttpResponse response = httpClient.execute(get);

            int internResponseStatus = response.getStatusLine().getStatusCode();

            if(200 == internResponseStatus)
            {
                BufferedReader rd = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));

                StringBuffer result = new StringBuffer();
                String line = "";
                while ((line = rd.readLine()) != null) {
                    result.append(line);
                }

                String userName = null;
                try {
                    JSONObject obj = new JSONObject(result.toString());
                    userName = obj.getString("SpotfireUser");
                } catch (JSONException ex) {
                }
                return new Identity(userName);                
            }else
            {
                return new AIdentity(null);                
            }

        } catch (IOException ex) {
            throw ex;
        } 
    }

    public class AIdentity implements IIdentity
    {
        private final String UserName;
        public AIdentity(String userName)
        {
            this.UserName = userName;
        }
        @Override
        public String getName() {
            return UserName;
        }

    }
}

这就是我使用它的方式 class

    import java.io.IOException;
    import java.security.Principal;
    import javax.servlet.http.*;
    import javax.servlet.Filter;
    import javax.servlet.FilterChain;
    import javax.servlet.FilterConfig;
    import javax.servlet.ServletContext;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;


    public class SpotfireAuthFilter implements Filter {

        private static final String AUTHENTICATION_SERVICE_URL_PARAM = "AUTHENTICATION_SERVICE_URL";
        private static final String COOKIE_NAME_PARAM = "COOKIE_NAME";



        private ServletContext context;    
        private String[] SpotfireTicketNames = null;
        private String[] AuthServiceBaseURLs = null;

        private IAuthenticator AuthService;

        @Override
        public void init(FilterConfig fc) throws ServletException {
            context = fc.getServletContext();

            if(null == fc.getInitParameter(AUTHENTICATION_SERVICE_URL_PARAM) 
                || null == fc.getInitParameter(COOKIE_NAME_PARAM) )
            {
                throw new ServletException("Can't read filter initial parameters");
            }

            AuthServiceBaseURLs = fc.getInitParameter(AUTHENTICATION_SERVICE_URL_PARAM).split(",");
            SpotfireTicketNames = fc.getInitParameter(COOKIE_NAME_PARAM).split(",");
            AuthService = new Authenticator();

            if(SpotfireTicketNames.length != AuthServiceBaseURLs.length)
            {
                throw new ServletException(
                        String.format("Count of '%s' parameter don't equal '%s' parameter", 
                                COOKIE_NAME_PARAM, 
                                AUTHENTICATION_SERVICE_URL_PARAM));
            }

        }

        @Override
        public final void doFilter(
                ServletRequest servletRequest,
                ServletResponse servletResponse,
                FilterChain chain)  throws ServletException 
        {
            final HttpServletRequest request = (HttpServletRequest) servletRequest;
            final HttpServletResponse response = (HttpServletResponse) servletResponse;

            try 
            {
                doFilter(request, response, chain);
            } 
            catch (IOException | RuntimeException e) 
            {
              // Not possible to authenticate, return a 401 Unauthorized status code without any WWW-Authenticate header

              sendError(response, 401, "Unauthorized");
            }
        }

        @Override
        public void destroy() {
         // do nothing   
        }

        private void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException 
        {

            String url = getAuthServiceURL(request);
            if(null != url)           
            {


                IIdentity identity = AuthService.doAuthentication(url);
                if(null != identity)
                {
                    String userName = identity.getName();
                    if(null != userName && !userName.equalsIgnoreCase(""))
                    {
                        Principal principal = createPrincipal(userName);

                        // Pass on the request to the filter chain and the authentication framework
                        // should pick up this priincipal and authenticate user
                        chain.doFilter(new WrappedHttpServletRequest(request, principal), response);


                    }
                    else
                    {
                        throw new IOException("Authentication failed");
                    }
                }else
                {
                    throw new IOException("Can't authenticate user by url " + url);
                }
            }
            else
            {
                throw new IOException("Can't find ticket to authenticate user.");
            }

            // Done!
            return;
        }

        private void sendError(HttpServletResponse response, int statusCode, String message) {
            try {
              response.sendError(statusCode, message);
            } catch (IOException e) {

            }
        }

        private String getAuthServiceURL(HttpServletRequest request) {

            Cookie[] cookies  = request.getCookies();
            for(int i =0; i< cookies.length; ++i)
            {
                for(int j =0; j< SpotfireTicketNames.length; ++j)
                {
                    if(cookies[i].getName().equalsIgnoreCase(SpotfireTicketNames[j]))
                    {
                        return String.format(AuthServiceBaseURLs[j], cookies[i].getValue());
                    }    
                }
            }
            return null;
        }


    private Principal createPrincipal(String username) 
    {

        // check does username contain domain/email/display name 
        return new APrincipal(username);
    }



    /**
     * A wrapper for {@link HttpServletRequest} objects.
     */
    private static class WrappedHttpServletRequest extends HttpServletRequestWrapper {

      private final Principal principal;

      public WrappedHttpServletRequest(HttpServletRequest request, Principal principal) {
        super(request);
        this.principal = principal;
      }

      @Override
      public Principal getUserPrincipal() {
        return this.principal;
      }

    } // WrappedHttpServletRequest
  }


    public class APrincipal implements Principal {
        private final String _username;

        public APrincipal(String username) {
           _username = username;
        }

        @Override
        public String getName() {
         return _username;   
        }

    }

以及这些初始参数