我目前正在用Java编写一个小型动态Web应用程序。 该应用程序应该是一个事件平台,您可以在其中创建用户帐户,登录,然后您可以看到所有打开的事件(在以后的迭代中,用户可以创建/参与这些事件)。
现在,web-app的结构可以(简化)描述如下:
Register-Servlet -> Register.jsp
|
V
Login-Servlet -> Login.jsp
|
V
Main-page-Servlet -> Main.jsp
现在,用户可以访问Login.jsp,他的登录信息将被发送到Login-Servlet,后者将对其进行验证,然后将其发送到Main-Page-Servlet。 然后,Main-Page-Servlet(在再次验证登录之后)从数据库获取所有当前事件,将其附加到请求,并将其转发到Main.jsp,Main.jsp显示它以供用户查看。
现在,如果用户想直接访问Main.jsp(没有来自Main-Page-Servlet),它显然无法显示可用事件。我正在使用的解决方法是进行空检查以查看事件是否存在,如果没有,则重定向到Main-Page-Servlet。
这让我很难解决我的问题,因为我认为这不是最好的做法,而且我认为它会在我的应用程序越大时产生许多其他问题。
我首先想到的是,如果我可以简单地“隐藏”用户的所有.jsp,那么用户可能只会登陆servlet并且无法以不同的方式访问.jsp。
有办法吗?或者,如果不是,如果我要编写专业的企业级应用程序,最佳实践解决方案是什么?
答案 0 :(得分:10)
这可以在Filter
中处理,StackOverflow Servlet-Filter wiki中有很好的解释和示例。
根据您的问题调整代码(请注意needsAuthentication
方法的添加和使用):
@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;
}
}
我建议将所有需要身份验证的网页移到app
这样的文件夹中,然后将网络过滤器更改为
@WebFilter("/app/*")
通过这种方式,您可以从过滤器中删除 needsAuthentication
方法。
答案 1 :(得分:0)
有几种方法可以做到这一点,例如上面的servlet过滤器。我在一些项目中看到他们通过创建一个通用动作(servlet)使用一种更简单的机制来完成此任务。因此,不是扩展HttpServlet,而是扩展所有servlet的通用操作。而且您可以实现很多常见的东西,例如身份验证,验证,权限...
以下是常见的操作示例:
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);
}
................
................
}
您的操作servlet如下:
@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");
.....