Каков наилучший способ реализации авторизации / контроля доступа в веб-приложении Spring 3 MVC? - PullRequest
4 голосов
/ 01 апреля 2012

Друзья,

Я собираюсь разработать веб-приложение, используя Spring 3 MVC в качестве веб-фреймворка, Hibernate Annotations как ORM. Однако я столкнулся с проблемой при разработке хорошего управления доступом на основе базы данных дляэто приложение.В моей работе мы привыкли проектировать так:

  • (CompanyName) User.java - класс, который означает User вsystem

  • Profile.java - класс, который означает ROLE в системе в отношениях NN с (CompanyName) Пользователь .Под ROLE я подразумеваю группу пользователей, например (ADMIN, ANONYMOUS, USER SERVICE USER и т. Д.)

  • UserProfile.java - класс, обозначающий отношения между пользователем и профилем .Он представляет JOIN TABLE для отношения NN в базе данных.

  • Module.java - класс, которыйозначает МОДУЛЬ в веб-приложении.Каждый модуль состоит из неограниченных функций, но каждая функция может быть связана только с одним MODULE .Например, функция USER AUTHENTICATION может быть связана с модулем SECURITY или AUTHENTICATION .Модули - это контроллеры в приложении, помеченные @ Controller.

  • Feature.java - класс, представляющий FEATURE в приложении.Каждая функция состоит из одной или нескольких операций.Например, УПРАВЛЕНИЕ ПОЛЬЗОВАТЕЛЕМ является ФУНКЦИЕЙ.И как таковой, он состоит из множества операций (например, CREATE, READ, UPDATE и DELETE USER).Кроме того, FEATURE имеет URL-адрес ENTRY, который представляет URL-адрес этой функции (для перенаправления пользователя на эту функцию при нажатии кнопки / ссылки).Каждый URL-адрес сопоставлен с методом в модуле (контроллере).

  • Operation.java - класс, представляющий OPERATION ввеб приложение.Операция в основном представляет собой одну / базовую операцию, такую ​​как REGISTER USER или REMOVE USER , но не обязательно операция CRUD.Каждая операция имеет ENTRY URL (URL, который показывает страницу, с которой начинается операция).Например, для операции РЕГИСТРАЦИЯ ПОЛЬЗОВАТЕЛЯ запись URL будет / имя веб-приложения / имя_модуля (ПОЛЬЗОВАТЕЛЬ) / имя_функции (УПРАВЛЕНИЕ ПОЛЬЗОВАТЕЛЕМ) / имя_операции (ЗАПИСАТЬ ПОЛЬЗОВАТЕЛЬ) .Но для операции может потребоваться выполнение потока страниц.Например, для операции USER REGISTRATION , вероятно, потребуется страница с формой регистрации, URL-адрес (обычно сопоставляемый с методом) в качестве действия для отправки формы и SUCCESS / ERROR страницы, чтобы показать сообщение SUCCESS / ERROR .

  • Permission.java - класс, представляющий URL в системе.Каждое Разрешение связано с 1 или многими ОПЕРАЦИЯМИ (Operation.java) для создания СТРАНИЦЫ ПОТОКА .Например: операция РЕГИСТРАЦИЯ ПОЛЬЗОВАТЕЛЯ , вероятно, будет иметь следующие URL / РАЗРЕШЕНИЯ :

    • / webapplicationName / moduleName (USER)/ featureName (УПРАВЛЕНИЕ ПОЛЬЗОВАТЕЛЕМ) / operationName (РЕГИСТРАЦИЯ ПОЛЬЗОВАТЕЛЯ) / register - URL-адрес, сопоставленный с методом в контроллере (CompanyNameUser) для отправки формы (действие формы) и для сохранения в базе данных, обычно вызывающей (CompanyNameUser)DAO

    • / webapplicationName / moduleName (USER) / featureName (USER MANAGEMENT) / operationName (REGISTER USER) / success / - URL-адрес, сопоставленный с методом вКонтроллер для отображения УСПЕХА СООБЩЕНИЯ

    • / webapplicationName / moduleName (USER) / featureName (USER MANAGEMENT) / operationName (REGISTER USER) / error / - сопоставленный URL-адреск методу в контроллере для отображения сообщения об ошибке

  • ProfilePermission.java - Класс, представляющий таблицу JOIN для N-N отношений между профилями и разрешениями.

Проблема здесь в том, что если я использую Spring Security для реализации контроля доступа, я обречен на реализацию класса User.java (я не могу изменить имя), также мне понадобится класс для ROLES и другой для AUTHORITIES. Итак, я не могу создать свой собственный поток управления доступом. Я подумал об использовании SERVLET FILTER для проверки разрешений на доступ / запрет доступа. Однако, когда я пытаюсь перенаправить на URL или просто выполнить chain.doFilter () внутри моего фильтра, он просто показывает ОШИБКУ 404. Я думаю, это потому, что я использую DefaultAnnotationHandlerMapping обрабатывать запросы. Тем не менее, мой конфиг выглядит следующим образом:

web.xml:

<?xml version="1.0" encoding="UTF-8"?>

<web-app version="2.5" 
   xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee     http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">`<display-name>cheapig</display-name>

<!-- ROOT CONTEXT DEFINITIONS -->
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/spring/root-context.xml</param-value>
</context-param>`
<listener>
    <listener-  class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener> 

<!-- The filter to implement my access control -->
<filter>
    <filter-name>securityFilter</filter-name>
    <filter-class>org.cheapig.security.SecurityFilter</filter-class>
</filter>

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

<servlet>
    <servlet-name>cheapig</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-   class>     <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/spring/cheapig/servlet-context.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>  

<servlet-mapping>
    <servlet-name>cheapig</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping></web-app>

корень-context.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"       
xmlns:tx="http://www.springframework.org/schema/tx" 
xmlns:context="http://www.springframework.org/schema/context"       
xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.1.xsd
    http://www.springframework.org/schema/tx
    http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
    http://www.springframework.org/schema/aop       
    http://www.springframework.org/schema/aop/spring-aop-3.1.xsd">
<!-- Root Context: defines shared resources visible to all other web components -->

<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
    <property name="basename" value="classpath:messages" />
    <property name="defaultEncoding" value="latin1"/>              
</bean>

<bean id="localeChangeInterceptor"
    class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
    <property name="paramName" value="lang" />      
</bean>

<bean id="localeResolver"
    class="org.springframework.web.servlet.i18n.CookieLocaleResolver">
    <property name="defaultLocale" value="pt"/>

</bean>

<bean id="handlerMapping"
    class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
   <property name="interceptors">
       <ref bean="localeChangeInterceptor" />
   </property>     
</bean></beans>

сервлетов контекст:

    <?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/mvc    http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd
    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">

    <!-- DispatcherServlet Context: defines this servlet's request-processing   infrastructure -->

    <!-- Enables the Spring MVC @Controller programming model -->
    <annotation-driven />

    <!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->
    <resources mapping="/resources/**" location="/resources/" />

    <!-- Imports user-defined @Controller beans that process client requests -->
    <beans:import resource="controllers.xml" />
    <beans:import resource="hibernateMySQL5.xml"/>      
    <context:component-scan base-package="br.com.cheapig" />
</beans:beans>

SecurityFilter.java:

package br.com.cheapig.security;

import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

public class SecurityFilter implements Filter {

@Override
public void init(FilterConfig filterConfig) throws ServletException {
    // TODO Auto-generated method stub

}

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

    // TODO Auto-generated method stub
    chain.doFilter(request, response);
}

@Override
public void destroy() {
    // TODO Auto-generated method stub
}
 }

Итак, что мне делать? Должен ли я использовать Spring Security? Есть ли способ реализовать мой собственный процесс с помощью Spring Security? Должен ли я использовать перехватчик в моем отображении обработчика вместо использования фильтра? Буду признателен за любую помощь / предложения.

Заранее спасибо!

Ответы [ 2 ]

2 голосов
/ 01 апреля 2012

Взгляните на Apache Shiro . Это может быть лучше подходит для ваших требований.

0 голосов
/ 19 ноября 2014

Это очень поздний ответ, но здесь речь пойдет о будущих поколениях.

Я согласен с sourcedelica , что Apache Shiro - это хорошее место для поиска.Однако, кроме того, я бы рекомендовал вам сделать шаг назад и взглянуть на теорию, стоящую за вашей проблемой.По сути, вы пытаетесь реализовать модель управления доступом на основе ролей с пользователями, группами, ролями и разрешениями.Кроме того, после прочтения вашего вопроса кажется, что у вас есть отношения между пользователями, запрашивающими доступ, и целевыми ресурсами.

Учитывая это, вам нужен ABAC - контроль доступа на основе атрибутов - как определено NISTв их отчете, выпущенном ранее в 2014 году. Вы можете прочитать отчет здесь .

С ABAC вы можете описать своих пользователей в терминах атрибутов - любых атрибутов - таких как роль, местоположение, возраст,гражданство ... Точно так же вы можете описывать ресурсы и объекты таким же образом, как и предпринятые действия и контекст.

Это означает, что с атрибутами и ABAC вы можете легко реализовать следующие требования авторизации:

  • пользователь с редактором role == может выполнить действие == edit для ресурсов типа == document, если и только если пользователь находится в том же отделе, что и ресурсы (user.department == resource.department)
  • пользователь может выполнить действие == удалить ресурс типа == документ, если и только еслиПользователь владеет документом (user.id == document.owner.id) и, если статус == черновик.

Чтобы реализовать ABAC, используйте XACML .XACML является расширяемым языком разметки контроля доступа, как определено OASIS.Он предоставляет вам:

  • схему запроса / ответа (как задавать вопросы и получать решения),
  • язык политики (конечно, на основе атрибутов) и
  • архитектура.

XACML Architecture

Google вокруг.Существует множество ресурсов XACML для Java.

Преимущества использования ABAC и XACML заключаются в том, что вы в конечном итоге лишаете свой контроль доступа от своей бизнес-логики, что означает, что вы можете изменять свое приложение независимо от логики авторизации инаоборот.

HTH

...