У меня есть сайт, использующий Java Сервлет и JSP, работающий на сервере apache tomcat8, я также использую Springboot 5 в качестве фреймворка и Hibernate в качестве ORM для получения информации в базе данных.
На этом сайте я использую атрибуты сеанса для управления информацией аутентификации пользователей (вместо, например, файлов cookie). У меня также есть Springboot Filter, который перехватывает ВСЕ traffi c на моем сайте, чтобы контролировать доступность запрашиваемой страницы определенным пользователем или нет.
Подробно, я реализовал 3 уровня проверок, там являются "административными" страницами, доступными только администраторам, "зарегистрированными" страницами, доступными для всех зарегистрированных пользователей, и всеми остальными страницами, доступными для всех пользователей, которые посещают мой сайт.
Когда пользователь заходит на мой сайт, для каждого запроса, который он отправляет на сервер, фильтр Springboot перехватывает запрос и проверяет, доступна ли запрашиваемая страница этому пользователю, проверяя атрибуты сеанса и «уровень безопасности страницы» (извините за имя, но я не знаю, как называть это). Если у пользователя нет прав на вход, он перенаправляется на страницу входа. Код выглядит следующим образом:
LoginServlet : вызывается путем отправки стандартной формы входа в систему при входе в систему. jsp
public class loginServlet extends HttpServlet{
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
String email = request.getParameter("email");
String password = request.getParameter("password");
/* Controls if User Exist in the Database based on username and password */
if(/* userNotExist */){
/*the attributes setted here is used in the login.jsp page to show
a login error message, or not in case the attributes are not setted*/
request.getSession().setAttribute("login.successfull", "LOGIN.ERROR");
request.getSession().setAttribute("logged", false);
response.sendRedirect("login.jsp");
}
else { //user Exist
//get the old session and invalidate if exist
HttpSession oldSession = request.getSession(false);
if (oldSession != null) {
oldSession.invalidate();
}
//generate a new session
HttpSession newSession = request.getSession(true);
//setting session to expiry in 10 mins
newSession.setMaxInactiveInterval(10*60);
/*Setting Attributes for this Session*/
newSession.setAttribute("login.successfull", "LOGIN.OK");
newSession.setAttribute("logged", true);
newSession.setAttribute("is.admin", workUser.getAdminVal());
newSession.setAttribute("user.username", workUser.getUsername());
newSession.setAttribute("user.email", workUser.getEmail());
newSession.setAttribute("user.uid", workUser.getUid());
/*Redirecting to survey page*/
response.sendRedirect("survey.jsp");
}
Когда пользователь выполняет вход в систему правильно, затем он перенаправляется на страницу опроса. jsp (страница доступна только зарегистрированным пользователям). Это перенаправление перехватывается authenticationFilter , который управляет атрибутами сеанса, которые были только что установлены в LoginServlet:
public class AuthenticationFilter implements Filter {
private ServletContext context;
public void init(FilterConfig fConfig) throws ServletException {
this.context = fConfig.getServletContext();
this.context.log("AuthenticationFilter initialized");
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
HttpSession session = req.getSession(false);
/* Retrieving page security level (checking a config.properties file) */
/* Retrieving requested page URI */
String requested_page = req.getRequestURI();
if(/* Page is accessible without login*/) {
//showing page clear, no login required
chain.doFilter(request, response);
}
else if (/* Page is accessible by logged users*/ ){
//login required
//check if user logged
if(!accessAuthorization(session, "logged")) {
//user not logged
this.context.log("Unauthorized access request");
//redirect to the login page
req.getSession().setAttribute("login.successfull", "LOGIN.REQUIRED");
res.sendRedirect("login.jsp");
}
else {
//session exist, user logged
chain.doFilter(request, response);
}
}
else if(/* Page accessible only by administrators*/) {
//login required, admin required too
if(!accessAuthorization(session, "admin")) {
//session not exist or user not admin
this.context.log("Unauthorized access request");
//redirect to error page
res.sendRedirect("error.jsp");
}
else { //user is logged and is admin, ok!
chain.doFilter(request, response);
}
}
}
Метод accessAuthorization , используемый в AuthenticationFilter проверяет, не является ли сеанс ненулевым, и оба атрибута logged
и is.admin
.
Хорошо, так что до вчерашнего дня все работало правильно, на HTTP-запросах. Этим утром я переключил свой домен на HTTPS. В частности, я настроил Let's Encrypt SSL Cert для Apache в Ubuntu 18.04, следуя онлайн-руководству.
Затем в своих настройках apache2 я включил 000-default-le-ssl.conf и отключено 000-default.conf . В 000-default-le-ssl.conf я добавил прокси в virtualHost для перенаправления всех запросов на порт 443 на стандартный порт 8080, на котором запущена служба tomcat:
<IfModule mod_ssl.c>
<VirtualHost *:443>
# The ServerName directive sets the request scheme, hostname and port that
# the server uses to identify itself. This is used when creating
# redirection URLs. In the context of virtual hosts, the ServerName
# specifies what hostname must appear in the request's Host: header to
# match this virtual host. For the default virtual host (this file) this
# value is not decisive as it is used as a last resort host regardless.
# However, you must set it for any further virtual host explicitly.
#ServerName www.example.com
ServerAdmin ### myserver@admin
DocumentRoot ### my/document/root
# Available loglevels: trace8, ..., trace1, debug, info, notice, warn,
# error, crit, alert, emerg.
# It is also possible to configure the loglevel for particular
# modules, e.g.
#LogLevel info ssl:warn
ServerName ### my.server.name
ServerAlias ### my.server.alias
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
# For most configuration files from conf-available/, which are
# enabled or disabled at a global level, it is possible to
# include a line for only one particular virtual host. For example the
# following line enables the CGI configuration for this host only
# after it has been globally disabled with "a2disconf".
#Include conf-available/serve-cgi-bin.conf
SSLCertificateFile ### my/certificate/file/path
SSLCertificateKeyFile ### my/private/key/file/path
Include /etc/letsencrypt/options-ssl-apache.conf
ProxyRequests Off
ProxyPreserveHost On
ProxyPass / http://my.site:8080/
ProxyPassReverse / http://my.site:8080/
</VirtualHost>
</IfModule>
Я ничего не изменял в конфигурационных файлах Tomcat.
Каждый раз, когда я пытаюсь войти, мой loginServlet устанавливает новый сеанс (как всегда), но теперь, когда происходит перенаправление перехватывается фильтром, сеанс пуст. Похоже, что loginServlet больше не устанавливает сеансы, что делает недоступными страницы, которые требовали разрешения для зарегистрированных пользователей. Кстати, консоль Springboot не выдает никакой ошибки, и, очевидно, сеанс недействителен где-то на этапе перенаправления. Кто-нибудь может мне помочь?