13

I'm currently writing a little dynamic web-application in Java. The application is supposed to be an event-platform where you can create a user-account, log in, and then you can see all open events (in a later iteration, users can create/participate in those events).

Right now, the structure of the web-app could be (simplified) described like this:

Register-Servlet -> Register.jsp
        |
        V
Login-Servlet -> Login.jsp
        |
        V
Main-page-Servlet -> Main.jsp

So right now, a user could go to Login.jsp, his login-information would be sent to the Login-Servlet, which would validate it and then send it to the Main-Page-Servlet. The Main-Page-Servlet then (after validating login again) gets all current events from a database, attaches it to the request, and forwards it to the Main.jsp, which displays it for the user to see.

Now, if a user wants to access the Main.jsp directly (without coming from the Main-Page-Servlet), it obviously can not display the available events. The workaround I'm using currently is doing a null-check to see if the events are there, and if not, redirect to the Main-Page-Servlet.

It bothers me to solve my problem like that, as I don't think that's the best practice and I think it will just create a lot of other problems the bigger my application gets.

My first thought about this was, that it might be useful if I could simply "hide" all .jsp's from the user, so the user would be landing on servlets only and could not access the .jsp's in a different way.

Is there a way to do that? Or, if not, what would be the best practice solution if I would be writing a professional enterprise-level application?

ROMANIA_engineer
  • 54,432
  • 29
  • 203
  • 199
MrTrustworthy
  • 416
  • 1
  • 4
  • 14

2 Answers2

13

This can be handled in a Filter and there are great explanation and example in StackOverflow Servlet-Filter wiki.

Adapting the code there for your problem (note the addition and usage of the needsAuthentication method):

@WebFilter("/*")
public class LoginFilter implements Filter {
    @Override
    public void init(FilterConfig config)
        throws ServletException {
        // If you have any <init-param> in web.xml, then you could get them
        // here by config.getInitParameter("name") and assign it as field.
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
        throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;
        HttpSession session = request.getSession(false);

        String requestPath = httpServletRequest.getRequestURI();

        if (needsAuthentication(requestPath) ||
            session == null ||
            session.getAttribute("user") == null) { // change "user" for the session attribute you have defined

            response.sendRedirect(request.getContextPath() + "/login"); // No logged-in user found, so redirect to login page.
        } else {
            chain.doFilter(req, res); // Logged-in user found, so just continue request.
        }
    }

    @Override
    public void destroy() {
        // If you have assigned any expensive resources as field of
        // this Filter class, then you could clean/close them here.
    }

    //basic validation of pages that do not require authentication
    private boolean needsAuthentication(String url) {
        String[] validNonAuthenticationUrls =
            { "Login.jsp", "Register.jsp" };
        for(String validUrl : validNonAuthenticationUrls) {
            if (url.endsWith(validUrl)) {
                return false;
            }
        }
        return true;
    }
}

I would recommend to move all the pages that require authentication inside a folder like app and then change the web filter to

@WebFilter("/app/*")

In this way, you can remove the needsAuthentication method from the filter.

Community
  • 1
  • 1
Luiggi Mendoza
  • 85,076
  • 16
  • 154
  • 332
  • wow, thank you. i suppose the question is solved by that, although it's going to take me a while to work through all of that :) – MrTrustworthy Aug 14 '13 at 20:06
  • @MrTrustworthy you're welcome. Just to add, if you're not using a Servlet 3.0 compliant application server like Tomcat 5 then you must configure the filter in the old way in the web.xml. Note that this is covered in the wiki link I've posted. – Luiggi Mendoza Aug 14 '13 at 20:08
  • +1, @MrTrustworthy If you want to configure it in web.xml manually that is If you are using servlets <3.0 there is a example I linked in my post.I suggest you to see that link once and Move to 3.0 as it is the latest version. – Suresh Atta Aug 14 '13 at 20:12
  • @sureshatta all that is covered in stackoverflow's servlet-filter wiki. You should check that link as well :) – Luiggi Mendoza Aug 14 '13 at 20:17
  • @Luiggi: Ahhh i just looked at your code for like 15 minutes and then it just snapped and i got it :D Only thing i don't get is why validNonAuthenticationUrls contains these strings, as those are the ones i want to make accessible only through the servlet (especially main.jsp). is there a mistake in my thinking? – MrTrustworthy Aug 14 '13 at 20:24
  • @MrTrustworthy it means you don't need authentication to access to these pages i.e. you don't need to be logged to register, to login nor to main. If the problem is *Main.jsp* then just remove it from there. Or even easier, as I said in my comment, move the *Main.jsp* and other pages that needs authentication inside an *app* folder and apply the filter only to this folder. – Luiggi Mendoza Aug 14 '13 at 20:26
  • ok great, that means it works like i thought it would. i'm just in the middle of implementing a feature, but implementing a filter is going to be the next thing. didn't expect such a quick stream of answers and help :D – MrTrustworthy Aug 14 '13 at 20:35
  • Just to finish up the question for: I have implemented the code now and it works like expected, solving my problem. I had to look up servlet-annotation, forward versus sendRedirect, Filters in general, but it also helped me understanding how a web-application gets build. – MrTrustworthy Aug 16 '13 at 02:52
1

There're several ways to do it such as servlet filter as above. I saw in some projects they use a simpler mechanism to do it by creating a common action (servlet). So instead of extends HttpServlet, all servlet will be extended the common action. And you can implement a lot of common stuffs such as authentication, validations, permissions...

Here's common action example:

public class CommonServlet extends HttpServlet {
................
................
protected boolean validate(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    response.setContentType("text/html; charset=UTF-8");
    request.setCharacterEncoding("UTF-8");

    String email = (String) request.getSession().getAttribute("email");
    Object salaryGroup = request.getSession().getAttribute("SALARY_GROUP");

    if (email == null || email.equals("")) {
        request.setAttribute("err", "You have not logged in");
        request.getRequestDispatcher("/login.jsp").forward(request, response);
        return false;
    }

................
................
}

public void setRoleAndValidate(HttpServletRequest request, HttpServletResponse response, String role)
        throws ServletException, IOException {
    if (!validate(request, response)) {
        return;
    }

    setRoleCode(role);
}
................
................

}

Your action servlet will be as below:

@WebServlet("/employeeManager")
public class EmployeeManager extends CommonServlet {
    private static final long serialVersionUID = 1L;

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws 
                 ServletException, IOException {
        request.setCharacterEncoding("UTF-8");
        setRoleAndValidate(request, response, Permission.EMPLOYEE_LIST.toString());

        String action = request.getParameter("action");
        .....

Here's the simple implementation

JavaEE guy
  • 174
  • 1
  • 4