Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Java EE (J2EE) и Spring > А как вы это делаете?


Автор: fidel 4.9.2006, 09:38
В веб-приложении при логине (логинятсья все юзеры) надо реализовать различные типы доступа, т.е. в зависимости от роли (админ, пользователь,продвинутый пользователь). реализавано все LoginServlet --> ControllerServlet(MVC) - который пренаправляет запросы. Например, если залогинился админ, то ему открывается админская часть и все остальные части приложения, залогинился юзер, только юзерская. Как это лучше реализовать?

Или может посоветуете где-нить скачать пример такого приложения.
Заранее спасибо.

Автор: tux 4.9.2006, 10:27
Проще реализовать в фильтре (обычно так и делается). Фильтры выполняются до сервлетов, поэтому мимо них никто не пройдет. Схема такая:
  • проверяешь есть ли в сессии атрибут с нужным именем. Если пользователь залогинен, атрибут должен быть. Если такового нет, делаешь редирект на страницу логина или, как вариант, делаешь стандартную идентификацию средствами браузера
  • на странице пользователь вводит имя и пароль, сервлет проверяет правильность имен и паролей и если все правильно, то в атрибут сессии помещает какой-то объект, идентифицирующий пользователя. В объекте можно хранить все что угодно - роли пользователя, его права, ну и т.п. В общем любую информацию, которая будет тебе нужна чтобы кастомизировать приложение в зависимости от того, что это за пользователь. Если же пользователь ввел имя и пароль неправильно, попросить его сделать это еще раз
  • если нужный атрибут в сессии есть, то просто ничего не делаешь и передаешь управление следующему фильтру.
Вот общая схема. Реализация зависит от приложения.

Автор: fidel 4.9.2006, 11:59
Спаибо, tux, за совет я в принципе все так и делаю, вот давайте начем с первого пункта, в пример естественно я приведу упрошенный без использования БД, есть LoginSevlet, на котором юзеры логиняться, если логин удачный то они переходят к RootControllerServlet - сервлет контролер в MVC, т.к. реализована модель MVC, нужно чтобы фильтр (SessionFilter) при попытке вызвать из RootControllerServlet какую-нить jsp (например, showUserAccounts.jsp) проверял наличие сессии, что бы нельзя было обойти процесс логона и просто в браузере набрать http://localhost:8080/app1/jsp/showUserAccounts.jsp. Мне подсказывали как это сделать на других форумах, но что то пока без результатно, может Вы поможите, итак листинги:

LoginServlet:
Код

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.servlet.ServletException;
import java.io.IOException;
import java.io.PrintWriter;

public class LoginServlet extends HttpServlet{

  public void doGet(HttpServletRequest request,
                    HttpServletResponse response)
  throws ServletException, IOException {
  sendLoginForm(response, false);
}

private void sendLoginForm(HttpServletResponse response,
                           boolean withErrorMessage)
  throws ServletException, IOException {

  response.setContentType("text/html");
  PrintWriter out = response.getWriter();
  out.println("<HTML>");
  out.println("<HEAD>");
  out.println("<TITLE>Login</TITLE>");
  out.println("</HEAD>");
  out.println("<BODY>");
  out.println("<CENTER>");

  if (withErrorMessage)
    out.println("Login failed. Please try again.<BR>");

  out.println("<BR>");
  out.println("<BR><H2>Login Page</H2>");
  out.println("<BR>");
  out.println("<BR>Please enter your user name and password.");
  out.println("<BR>");
  out.println("<BR><FORM METHOD=POST>");
  out.println("<TABLE>");
  out.println("<TR>");
  out.println("<TD>User Name:</TD>");
  out.println("<TD><INPUT TYPE=TEXT NAME=userName></TD>");
  out.println("</TR>");
  out.println("<TR>");
  out.println("<TD>Password:</TD>");
  out.println("<TD><INPUT TYPE=PASSWORD NAME=password></TD>");
  out.println("</TR>");
  out.println("<TR>");
  out.println("<TD ALIGN=RIGHT COLSPAN=2>");
  out.println("<INPUT TYPE=SUBMIT VALUE=Login></TD>");
  out.println("</TR>");
  out.println("</TABLE>");
  out.println("</FORM>");
  out.println("</CENTER>");
  out.println("</BODY>");
  out.println("</HTML>");
}

public void doPost(HttpServletRequest request,
                   HttpServletResponse response)
  throws ServletException, IOException {

    String userName = request.getParameter("userName");
    String password = request.getParameter("password");

    if (login(userName, password)){

        HttpSession session = request.getSession(true);
       session.setAttribute("loggedIn", new String("true"));
       response.sendRedirect("RootControllerServlet");
         }else{
        sendLoginForm(response, true);
    }
}
      public Boolean login(String userName, String password){

          if (userName.equals("1") && password.equals("1")){
                return true;
             }
          else return false;
      }


RootControllerServlet:
Код

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.servlet.ServletException;
import javax.servlet.RequestDispatcher;
import java.io.IOException;

public class RootControllerServlet extends HttpServlet {

    public String loginUrl = "LoginServlet";

    public void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {

         try{
        HttpSession session = request.getSession();
        if(session == null)
           response.sendRedirect(loginUrl);
         else{
            String loggedIn = (String) session.getAttribute("loggedIn");
            if (!loggedIn.equals("true"))
            response.sendRedirect(loginUrl);
        }
         } catch(NullPointerException e) {}
        doPost(request, response);
      }

      public void doPost(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException{

          String base = "/jsp/";
          String url = base + "Default.jsp";
          String action = request.getParameter("action");
                if (action!=null) {
                if (action.equals("showUserAccounts") ||
                   (action.equals("deleteUserAccount")))
                url = base + "showUserAccounts.jsp";

                 else if (action.equals("createNewUserAccount") ||
                        (action.equals("createUser")))
                 url = base + "createNewUserAccount.jsp";

                 else if (action.equals("logOff"))
                 response.sendRedirect(loginUrl);
              }

           RequestDispatcher requestDispatcher = getServletContext().getRequestDispatcher(url);
           requestDispatcher.forward(request, response);
         }
    }


SessionFilter:
Код

import java.io.*;
import javax.servlet.*;
import javax.servlet.Filter;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletRequest;

public class SessionFilter implements Filter{
  public String loginUrl = "LoginServlet";
  private FilterConfig filterConfig = null;

     public void init(FilterConfig filterConfig) throws ServletException {
        this.filterConfig = filterConfig;
    }

    public void doFilter(ServletRequest request, ServletResponse response,
                         FilterChain chain) throws ServletException, IOException {

        ServletContext servletContext = filterConfig.getServletContext();
        HttpServletRequest req = (HttpServletRequest) request;
        HttpSession session = req.getSession();
        String loggedIn = (String) session.getAttribute("loggedIn");

        if (!"true".equals(loggedIn)) {
            chain.doFilter(request, response);
                }
        else {
             ((HttpServletResponse) response).sendRedirect(loginUrl);
        }
      }
    public void destroy(){
        this.filterConfig = null;
    }
}

web.xml:
Код

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>

<servlet>
        <servlet-name>LoginServlet</servlet-name>
        <servlet-class>LoginServlet</servlet-class>
     </servlet>

    <servlet>
        <servlet-name>RootControllerServlet</servlet-name>
        <servlet-class>RootControllerServlet</servlet-class>

        <init-param>
            <param-name>base</param-name>
            <param-value>http://127.0.0.1:8080/test_f/RootControllerServlet</param-value>
        </init-param>
                   
     </servlet>
       <servlet-mapping>
          <servlet-name>LoginServlet</servlet-name>
          <url-pattern>/LoginServlet</url-pattern>
    </servlet-mapping>

    <servlet-mapping>
         <servlet-name>RootControllerServlet</servlet-name>
         <url-pattern>/RootControllerServlet</url-pattern>
    </servlet-mapping>

    <filter>
        <filter-name>SessionFilter</filter-name>
        <filter-class>SessionFilter</filter-class>
    </filter>

    <filter-mapping>
        <filter-name>SessionFilter</filter-name>
        <servlet-name>RootControllerServlet</servlet-name>
    </filter-mapping>

</web-app>


ну еще 
showUserAccounts.jsp:
Код

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head><title>showUserAccounts</title></head>
  <body>showUserAccounts</body>
</html>


 Не работает, к сожалению! Подскажите, что не так?

Автор: tux 4.9.2006, 12:22
Вообще говоря, никакой зависимости между сервлетами и JSP нет. Откуда фильтру знать, что страница JSP по адресу  http://localhost:8080/app1/jsp/showUserAccounts.jsp используется сервлетом RootControllerServlet.? А фильтр привязан у тебя только к этому сервлету. Поэтому советую повесить фильтр на все ресурсы и независимо от того что пользователь набирает и на какие ссылки переходит этот фильтр будет срабатывать и редиректить пользователя на страницу логина если он еще не вводил имя и пароль. В общем что-то такое в маппинге фильтра:
Код

<filter-mapping>
    <filter-name>SessionFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>


Автор: fidel 4.9.2006, 13:44
вот бы какой-нить примерчик посмотреть

Автор: tux 4.9.2006, 17:14
Цитата(fidel @  4.9.2006,  18:44 Найти цитируемый пост)
вот бы какой-нить примерчик посмотреть 

А чего на него смотреть? Ты попробовал маппинг фильтра у себя поменять? Если пробовал, то что получилось?

Автор: fidel 5.9.2006, 09:01
пробывал, не помогает.
 Вот вчера вечером мысля на меня нашла: а что если вовсе не использовать фильтр, а при логине пользователя, если логин проходит создать сессию и в нее любимую загнать все свойства пользователя, а потом на jsp проверять. Мне кажеться намного гибче система. Например, есть у меня в приложении условных 15 действий (читать разные таблицы, вносить измениния в разные таблицы) - соответственно 15 jsp-страниц. В БД в таблице users будет дополнительно 15 полей, каждое из которых будет иметь true или false. Например, страница create_new_record.jsp, будет доступна, если в сессии залогинившегося пользователя атрибут "create_new_record" имеет значение "true".
Вопрос: на производительность приложения не сильно повлияет, если одновременно работает скажем 200 юзеров? Куда приложение сохраняет текущую сессию?

Автор: tux 5.9.2006, 12:07
Цитата(fidel @  5.9.2006,  14:01 Найти цитируемый пост)
пробывал, не помогает.

Ты скажи наконец что не получается-то. Предлагаешь на кофейной гуще погадать? У меня вот сейчас Hibernate сконфигурировать ручками не получается (как ни покажется странным), скажи, в чем причина? 

У тебя пользователи в RootControllerServlet попадают без логина? Так в коде фильтра ошибочка. 
Код

if (!"true".equals(loggedIn)) {
    chain.doFilter(request, response);
} else {
    ((HttpServletResponse) response).sendRedirect(loginUrl);

Здесь у тебя условие будет истинным поскольку loggedIn всегда будет равным null - в сессии ничего нет поскольку на LoginServlet не выполнялся.

Что касается распределения прав доступа то на мой взгляд не самое лучшее решение. Вот смотри. Предположим, что у тебя есть страница JSP, на которой ты будешь редактировать пользователей. На нее назначаешь права для пользователей. Потом оказалось, что тебе нужно чтобы администраторы могли редактировать данные всех пользователей, а суперюзеры только данные обычных пользователей системы. И вся система безопасности сразу рушится поскольку в ее рамках разделить права ты не сможешь. Или такой вариант. Не думаю что у тебя при редактировании пользователей используется одна страница JSP - нужны как минимум форма списка пользователей, форма редактирования пользователей. Хотя можно их конечно совместить, но это не суть важно. Так вот чтобы разрешить пользователю нужное действие, нужно будет задавать права на обе страницы, что тоже не есть хорошо. Поэтому предлагаю задавать права именно на уровне действий, например, "редактирование данных пользователя", "редактирование задач", "еще чего-то" и уже в зависимости от наличия такого права решать переходить на нужную страницу или выдавать экран с ошибкой о несанкционированном доступе.

Цитата(fidel @  5.9.2006,  14:01 Найти цитируемый пост)
на производительность приложения не сильно повлияет, если одновременно работает скажем 200 юзеров?

Обычно при проверке прав доступа выполняются более ресурсоемкие задачи, у тебя простое приложение.

Цитата(fidel @  5.9.2006,  14:01 Найти цитируемый пост)
Куда приложение сохраняет текущую сессию? 

Никуда не пишет. Сессией управляет веб-контейнер - создает, удаляет, предоставляет пользователю интерфейс для работы с ней. Пользователь сессию только использует.

Автор: fidel 5.9.2006, 12:38
 Спасибо! Тогда такой вопрос: что значит Ваша фраза : Обычно при проверке прав доступа выполняются более ресурсоемкие задачи?

Автор: tux 5.9.2006, 12:48
Цитата(fidel @  5.9.2006,  17:38 Найти цитируемый пост)
что значит Ваша фраза : Обычно при проверке прав доступа выполняются более ресурсоемкие задачи? 

Это значит что используемые в промышленных приложениях системы безопасности гораздо сложнее, соответственно и объемопераций при определении прав доступа выполняется гораздо больший. 

Автор: sergakrem 6.9.2006, 00:32
fidel, есть реализация такого.

Посмотри пожалуйста топик:

http://forum.vingrad.ru/index.php?showtopic=110539&view=findpost&p=844035

Судя по твоему вопросу - это именно то, что может тебе помочь.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)