问题
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?
回答1:
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.
回答2:
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
来源:https://stackoverflow.com/questions/18241008/how-can-i-handle-restrict-user-access-to-servlets-jsps