Две сферы в одном приложении с Spring Безопасность?

Мы создаем веб-приложение, доступное как для аутентифицированных, так и для анонимных пользователей. Если вы решите не регистрироваться/войти, у вас есть только ограниченный набор функций. Аутентификация пользователя выполняется по OpenID с помощью Spring Security. Это прекрасно работает.

Однако приложение также поставляется с пользовательским интерфейсом администратора, который развертывается в <host>/<context-root>/admin. Можем ли мы иметь две отдельные сферы с помощью Spring Безопасность (например, базовый auth для /admin/**)? Как это нужно настроить?

Ответы

Ответ 1

Spring Безопасность добавила поддержку для этого сценария в версии 3.1, которая в настоящее время доступна как кандидат на выпуск. Это было реализовано SEC-1171, а подробности синтаксиса приведены в руководстве, включенном в 3.1.

Однако он довольно прост в использовании. В основном вы просто определяете несколько элементов http в конфигурации Spring Security, по одному для каждой области. Мы используем его следующим образом:

<!-- Configure realm for system administration users -->
<security:http pattern="/admin/**" create-session="stateless">
    <security:intercept-url pattern='/**' access='ROLE_ADMIN' requires-channel="https" />
    <security:http-basic/>  
</security:http>


<!-- Configure realm for standard users -->
<security:http auto-config="true" access-denied-page="/error/noaccess" use-expressions="true" create-session="ifRequired">
    <security:form-login login-page="/login"
            ...
            ...
</security:http>

Ключевым моментом является pattern="/admin/**" для первого элемента http. Это сообщает Spring, что все URL-адреса под /admin подчиняются этой области, а не области по умолчанию, и поэтому URL-адреса под /admin используют вместо этого базовую проверку подлинности.

Ответ 2

Возможное решение:

  • Добавить перехватчик URL для /admin требуется "ROLE_ADMIN"
  • Настроить экземпляр org.springframework.security.web.authentication.www.BasicAuthenticationFilter для перехвата URL /admin и аутентификации пользователя как ROLE_ADMIN, если он предоставляет соответствующие учетные данные

Пример конфигурации:

<security:intercept-url pattern="/admin" access="ROLE_ADMIN"/>

<bean id="basicAuthenticationEntryPoint" 
      class="org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint">
    <property name="realmName" 
              value="WS realm"/>
</bean>

<bean id="basicAuthenticationProcessingFilter"
      class="org.springframework.security.web.authentication.www.BasicAuthenticationFilter">
    <property name="authenticationManager" 
              ref="authenticationManager"/>
    <property name="authenticationEntryPoint" 
              ref="basicAuthenticationEntryPoint"/>    
</bean>

Примечание: реализация по умолчанию BasicAuthenticationFilter - это пассивный фильтр, т.е. он просто ищет базовый заголовок auth в запросе, а если нет - ничего не делает. Если вы хотите, чтобы фильтр явно запрашивал базовую аутентификацию от клиента, вам необходимо расширить реализацию по умолчанию, чтобы перейти к точке входа в аутентификацию:

public class BasicAuthenticationFilter 
       extends org.springframework.security.web.authentication.www.BasicAuthenticationFilter {

    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {

        final HttpServletRequest request = (HttpServletRequest) req;
        final HttpServletResponse response = (HttpServletResponse) res;

        String header = request.getHeader("Authorization");

        if ((header != null) && header.startsWith("Basic ")) {
            super.doFilter(req, res, chain);
        } else {
            getAuthenticationEntryPoint().commence(request, response, new AuthenticationCredentialsNotFoundException("Missing credentials"));
        }
    }
}

Кроме того, вам нужно настроить фильтр для применения только к URL /admin - либо путем жесткого кодирования в методе doFilter, либо путем предоставления соответствующей оболочки bean.

Ответ 3

Я не могу думать о прямом способе иметь две сферы (и сам я не пробовал):

вы можете определить два фильтра в вашем web.xml, где каждая из них имеет другую конфигурацию spring и ergo собственную среду. Глобальные вещи входят в конфигурацию приложения, специфичную для области в конфигурации фильтра.

если он используется только для другого метода auth, вы можете написать свой собственный фильтр, который затем решает, какой фильтр вызывать.