4.3. The ClientFor each request, a servlet has the ability to find out about the client machine and, for pages requiring authentication, about the actual user. This information can be used for logging access data, associating information with individual users, or restricting access to certain clients. 4.3.1. Getting Information About the Client MachineA servlet can use getRemoteAddr() and getRemoteHost() to retrieve the IP address and hostname of the client machine, respectively: public String ServletRequest.getRemoteAddr() public String ServletRequest.getRemoteHost() Both values are returned as String objects. The information comes from the socket that connects the server to the client, so the remote address and hostname may be that of a proxy server. An example remote address might be "192.26.80.118" while an example remote host might be "dist.engr.sgi.com". The IP address or remote hostname can be converted to a java.net.InetAddress object using InetAddress.getByName() : InetAddress remoteInetAddress = InetAddress.getByName(req.getRemoteAddr()); 4.3.2. Restricting Access to the United States and CanadaDue to the United States government's policy restricting the export of strong encryption outside the United States and Canada, some web sites must be careful about who they let download certain software. Servlets, with their ability to find out about the client machine, are well suited to enforce this restriction. These servlets can check the client machine and provide links for download only if the client appears to be coming from inside the United States or Canada. Example 4-5 gives an example. Example 4-5. Can they be trusted?import java.io.*; import java.net.*; import java.util.*; import javax.servlet.*; import javax.servlet.http.*; public class ExportRestriction extends HttpServlet { public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { res.setContentType("text/html"); PrintWriter out = res.getWriter(); // ...Some introductory HTML... // Get the client's hostname String remoteHost = req.getRemoteHost(); // See if the client is allowed if (! isHostAllowed(remoteHost)) { out.println("Access <BLINK>denied</BLINK>"); // filter out the blink! } else { out.println("Access granted"); // Display download links, etc... } } // We assume hosts ending with .com, .edu, .net, .org, // .gov, .mil, .us, and .ca are legal even though this is an // over-simplification now that .com, .net, and .org have // become global top-level domains. We also assume // clients without a domain name are local and that // local is allowed. (After all, if local isn't allowed // you would have to be outside the United States and Canada -- so // why would you be using this servlet?) private boolean isHostAllowed(String host) { return (host.endsWith(".com") || host.endsWith(".edu") || host.endsWith(".net") || host.endsWith(".org") || host.endsWith(".gov") || host.endsWith(".mil") || host.endsWith(".us") || host.endsWith(".ca") || (host.indexOf('.') == -1)); // no domain, assume OK } } This servlet gets the client hostname with a call to req.getRemoteHost() and, based on its suffix, decides if the client came from inside or outside the United States and Canada. Of course, be sure to get high-priced legal counsel before making any cryptographic code available for download. 4.3.3. Getting Information About the UserWhat do you do when you need to restrict access to some of your web pages but want to have a bit more control over the restriction than this "continent by continent" approach? Say, for example, you publish an online magazine and want only paid subscribers to read the articles. Well (prepare yourself), you don't need servlets to do this. Nearly every HTTP server has a built-in capability to restrict access to some or all of its pages to a given set of registered users. How you set up restricted access depends on the server, but here's how it works mechanically. The first time a browser attempts to access one of these pages, the HTTP server replies that it needs special user authentication. When the browser receives this response, it usually pops open a window asking the user for a name and password appropriate for the page, as shown in Figure 4-1. Figure 4-1. Please log inOnce the user enters his information, the browser again attempts to access the page, this time attaching the user's name and password along with the request. If the server accepts the name/password pair, it happily handles the request. If, on the other hand, the server doesn't accept the name/password pair, the browser is again denied and the user swears under his breath about forgetting yet another password. How does this involves servlets? When access to a servlet has been restricted by the server, the servlet can get the name of the user that was accepted by the server, using the getRemoteUser() method: public String HttpServletRequest.getRemoteUser() Note that this information is retrieved from the servlet's HttpServletRequest object, the HTTP-specific subclass of ServletRequest. This method returns the name of the user making the request as a String or null if access to the servlet was not restricted. There is no comparable method to get the remote user's password (although it can be manually determined, as shown in Chapter 8, "Security"). An example remote user might be "jhunter". A servlet can also use the getAuthType() method to find out what type of authorization was used: public String HttpServletRequest.getAuthType() This method returns the type of authorization used or null if access to the servlet was not restricted. The most common authorization types are "BASIC" and "DIGEST". By the time the servlet calls getRemoteUser() , the server has already determined that the user is authorized to invoke the servlet, but that doesn't mean the remote user's name is worthless. The servlet could perform a second authorization check, more restrictive and dynamic than the server's. For example, it could return sensitive information about someone only if that person made the request, or it could enforce a rule that each user can make only 10 accesses per day.[2]
Then again, the client's name can simply tell the servlet who is accessing it. After all, the remote host is not necessarily unique to one user. Unix servers often host hundreds of users, and gateway proxies can act on behalf of thousands. But bear in mind that access to the client's name comes with a price. Every user must be registered with your server and, before accessing your site, must enter his name and password. Generally speaking, authentication should not be used just so a servlet can know to whom it is talking. Chapter 7, "Session Tracking", describes some better, lower-maintenance techniques for knowing about users. However, if a servlet is already protected and has the name easily available, the servlet might as well use it. With the remote user's name, a servlet can save information about each client. Over the long term, it can remember each individual's preferences. For the short term, it can remember the series of pages viewed by the client and use them to add a sense of state to a stateless HTTP protocol. The session tracking tricks from Chapter 7, "Session Tracking" may be unnecessary if the servlet already knows the name of the client user. 4.3.4. A Personalized WelcomeA simple servlet that uses getRemoteUser() can greet its clients by name and remember when each last logged in, as shown in Example 4-6. Example 4-6. Hey, I remember you!import java.io.*; import java.util.*; import javax.servlet.*; import javax.servlet.http.*; public class PersonalizedWelcome extends HttpServlet { Hashtable accesses = new Hashtable(); public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { res.setContentType("text/html"); PrintWriter out = res.getWriter(); // ...Some introductory HTML... String remoteUser = req.getRemoteUser(); if (remoteUser == null) { out.println("Welcome!"); } else { out.println("Welcome, " + remoteUser + "!"); Date lastAccess = (Date) accesses.get(remoteUser); if (lastAccess == null) { out.println("This is your first visit!"); } else { out.println("Your last visit was " + accesses.get(remoteUser)); } if (remoteUser.equals("PROFESSOR FALKEN")) { out.println("Shall we play a game?"); } accesses.put(remoteUser, new Date()); } // ...Continue handling the request... } } This servlet uses a Hashtableto save the last access time for each remote user. The first thing it does for each request is greet the person by name and tell him the time of his last visit. Then it records the time of this visit, for use next time. After that, it continues handling the request. Copyright © 2001 O'Reilly & Associates. All rights reserved. |
|