Как я могу обрабатывать/ограничивать доступ пользователей к сервлетам и jsp?
В настоящее время я пишу небольшое динамическое веб-приложение на Java.
Предполагается, что приложение является платформой событий, где вы можете создать учетную запись пользователя, войти в систему, а затем просмотреть все открытые события (на более поздней итерации пользователи могут создавать/участвовать в этих событиях).
В настоящее время структура веб-приложения может быть (упрощена) описана следующим образом:
Register-Servlet -> Register.jsp
|
V
Login-Servlet -> Login.jsp
|
V
Main-page-Servlet -> Main.jsp
Итак, прямо сейчас пользователь может перейти на Login.jsp, его информация для входа будет отправлена в Login-Servlet, который будет проверять его, а затем отправить на главный сервлет.
Затем с помощью Main-Page-Servlet (после подтверждения входа в систему) получает все текущие события из базы данных, прикрепляет их к запросу и перенаправляет его на Main.jsp, который отображает его для просмотра пользователем.
Теперь, если пользователь хочет получить доступ к Main.jsp напрямую (без выхода из Main-Page-Servlet), он, очевидно, не может отображать доступные события. Обходной путь, который я использую в настоящее время, выполняет нулевую проверку, чтобы увидеть, есть ли там события, а если нет, перенаправляйтесь к главному сервлету.
Меня это беспокоит, так как я не думаю, что лучшая практика, и я думаю, что это просто создаст много других проблем, чем больше мое приложение получит.
Моя первая мысль об этом заключалась в том, что было бы полезно, если бы я мог просто "скрыть" все .jsp от пользователя, так что пользователь будет садиться только на сервлеты и не сможет получить доступ к .jsp по-другому.
Есть ли способ сделать это? Или, если нет, каково было бы лучшее решение, если бы я писал профессиональное приложение на уровне предприятия?
Ответы
Ответ 1
Это можно обрабатывать в Filter
, и есть большие объяснения и примеры в StakeOverflow 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
из фильтра.
Ответ 2
Есть несколько способов сделать это, например, фильтр сервлетов, как указано выше. Я видел, что в некоторых проектах они используют более простой механизм для создания общего действия (сервлет). Таким образом, вместо расширения HttpServlet, все сервлеты будут расширены общим действием. И вы можете реализовать много общих вещей, таких как аутентификация, проверки, разрешения...
Вот пример общего действия:
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);
}
................
................
}
Ваш сервлет действий будет таким, как показано ниже:
@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");
.....
Здесь простая реализация