Sunday, September 4, 2011

User Authentication via Sessions

We've already seen sessions that were created implicitly in the ShoppingCartServlet. The sessions were created as needed and only used to identify an anonymous user.

Sessions can also be used for authentication. In contrast to HTTP Basic Authentication a session can be invalidated which enables users to log out without quitting the Web Browser (which is required with Basic Authentication because there is no way to force a browser to delete the authentication credentials).

The following SessionAuthServlet shows how to do authentication with a Servlet. The doPost method processes requests to log in or out. sendPage is called by both, doGet and doPost.

 
 1:  import java.io.*;
 2:  import javax.servlet.*;
 3:  import javax.servlet.http.*;
 4:
 5:  public final class SessionAuthServlet extends HttpServlet
 6:  {
 7:    protected void doGet(HttpServletRequest req, HttpServletResponse res)
 8:              throws ServletException, IOException
 9:    {
10:      sendPage(req, res, req.getSession(false));
11:    }
12:
13:    protected void doPost(HttpServletRequest req, HttpServletResponse res)
14:              throws ServletException, IOException
15:    {
16:      if(req.getParameter("login") != null)
17:      {
18:        HttpSession session = req.getSession(true);
19:        String name = req.getParameter("name");
20:        if(name == null || name.length()==0) name = "Anonymous";
21:        session.putValue("name", name);
22:        sendPage(req, res, session);
23:      }
24:      else
25:      {
26:        HttpSession session = req.getSession(false);
27:        if(session != null) session.invalidate();
28:        sendPage(req, res, null);
29:      }
30:    }
31:
32:    private void sendPage(HttpServletRequest req, HttpServletResponse res,
33:                          HttpSession session)
34:            throws ServletException, IOException
35:    {
36:      res.setContentType("text/html");
37:      res.setHeader("pragma", "no-cache");
38:      PrintWriter o = res.getWriter();
39:      o.print("<HTML><HEAD><TITLE>SessionAuthServlet</TITLE></HEAD><BODY>");
40:      if(session == null)
41:        o.print("<FORM METHOD=POST>Please enter your name: "+
42:                "<INPUT TYPE=TEXT NAME=\"name\">"+
43:                "<INPUT TYPE=SUBMIT NAME=\"login\" VALUE=\"Log in\">"+
44:                "</FORM></BODY></HTML>");
45:      else
46:        o.print("Hi " + session.getValue("name") +
47:                "<P><FORM METHOD=POST><INPUT TYPE=SUBMIT NAME=\"logout\" "+
48:                "VALUE=\"Log out\"></FORM></BODY></HTML>");
49:      o.close();
50:    }
51:  }
 

Relative URLs

When a Servlet creates a response which contains a relative URL, e.g. a hyperlink in an HTML document, you have to make sure that the URL points to the right directory.

Example. The following document is mounted on a server as /shop/preview/form.html:

<HTML><HEAD><TITLE>Form</TITLE></HEAD><BODY>
<FORM ACTION="/servlet/PreviewServlet" METHOD=GET>
...
</FORM>
</BODY></HTML>
 
There are also product images in the same directory, e.g. /shop/preview/foo.gif, /shop/preview/bar.gif, ...

The Servlet which is mounted as /servlet/PreviewServlet evaluates the form data and creates an HTML page with IMG tags to the appropriate product images, e.g. <IMG SRC="foo.gif">. But this naive approach does not work. The images are in the same directory as the form but the page is created by the Servlet, so the client sees it as /servlet/PreviewServlet. The base name of this URL is /servlet/, thus the image foo.gif from the above image tag is expected at /servlet/foo.gif and not /shop/preview/foo.gif. If /servlet/ is a pure Servlet directory it can only contain Servlets and no other data (like GIF images). It is therefore not possible to move the images to the Servlet directory (/servlet/). Instead the image tags need to be modified to include the full path to the images, relative to the server root, i.e. <IMG SRC="/shop/preview/foo.gif"> for the foo.gif image.

Logging

A Web Server is usually running as a background process without connected stdio streams. Even if the server is running in a console, a Servlet can not expect to access that console with the System.in, System.out and System.err streams. Instead all messages should be sent to a server log file with one of ServletContext's log methods:
  • public void log(String msg) writes the specified message to the log file.
  • public void log(String msg, Throwable t) API 2.1 writes the specified message and a stack trace of the Throwable object to the log file. The message will usually be an explanation of an error and the Throwable an exception that caused the error.
  • public void log(Exception exception, String msg) does the same as the previous method. It is available in earlier API versions and deprecated in version 2.1.
Two convenience methods are implemented in GenericServlet. They automatically prefix the messages with the right Servlet name and then call the appropriate ServletContext method:
  • public void log(String msg)
  • public void log(String msg, Throwable cause) API 2.1
Exceptions which cause one of the Servlet lifecycle methods (or a do... method in an HttpServlet) to fail do not need to be caught and logged. They are handled automatically by the Servlet Engine.

 Source : http://www.novocode.com


 


No comments:

Post a Comment