Управление сеансом в Spring Security

Я новичок в Spring Security. У меня есть требование выполнить аутентификацию на основе URL-адреса, при которой пользователь должен пройти аутентификацию на основе уникальной ссылки, которая будет отправляться каждый раз в качестве параметра в URL-адресе. Я передам эту ссылку веб-сервису, получу необходимые данные, а затем аутентифицирую пользователя (и установлю роли). Часть аутентификации и авторизации работает нормально.

Однако, когда я снова пытаюсь получить доступ к приложению (теперь с другой ссылкой в ​​URL-адресе), он говорит: «SecurityContextHolder не заполнен анонимным токеном, поскольку он уже содержит ...» и показывает детали предыдущего запроса. Я пробовал очистить контекст безопасности с помощью SecurityContextHolder.getContext (). SetAuthentication (null) и SecurityContextHolder.clearContext ().

После этого я мог получить доступ к приложению несколько раз. Однако, если я пытаюсь одновременно получить доступ к приложению с компьютера моих коллег, я получаю пустую страницу. После проверки журналов я вижу сообщение «SecurityContextHolder не заполнен анонимным токеном ...». Я также пробовал настраивать сеансы, но не знаю, где я сбиваюсь с пути.

Ниже мой web.xml (только часть безопасности Spring):

<filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>

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

<listener>
<listener-class>
          org.springframework.web.context.ContextLoaderListener
    </listener-class>
</listener>

<listener>
    <listener-class>
          org.springframework.security.web.session.HttpSessionEventPublisher
    </listener-class>
</listener>

<session-config>
<session-timeout>30</session-timeout>
</session-config>

spring -security.xml:

<http use-expressions="true" auto-config="false" entry-point-                   
                            ref="http403ForbiddenEntryPoint">
<intercept-url pattern="/paymentPortalInternal.*" access="hasRole('Internal')"/>
<intercept-url pattern="/paymentPortalExternal.*" access="hasRole('External')"/>

<custom-filter position="PRE_AUTH_FILTER" ref="customAuthenticationFilter"/>
<custom-filter position="CONCURRENT_SESSION_FILTER" ref="concurrencyFilter" />
<session-management session-authentication-strategy-ref="sas"/>
</http>

<beans:bean id="concurrencyFilter"
class="org.springframework.security.web.session.ConcurrentSessionFilter">
<beans:property name="sessionRegistry" ref="sessionRegistry" />
<beans:property name="expiredUrl" value="/session-expired.htm" />
</beans:bean>

<beans:bean id="http403ForbiddenEntryPoint"
  class="org.springframework.security.web.authentication.Http403ForbiddenEntryPoint"/>
<beans:bean id="customAuthenticationFilter"
  class="com.xxx.xxx.xxxxx.security.CustomAuthenticationFilter">
      <beans:property name="sessionAuthenticationStrategy" ref="sas" />
  <beans:property name="authenticationManager" ref="authenticationManager" />
</beans:bean>

<beans:bean id="sas" 
              class="org.springframework.security.web.authentication.session.
                                               ConcurrentSessionControlStrategy">
<beans:constructor-arg name="sessionRegistry" ref="sessionRegistry" />
<beans:property name="maximumSessions" value="1" />
<beans:property name="exceptionIfMaximumExceeded" value="true" />
</beans:bean>

<beans:bean id="sessionRegistry"    
class="org.springframework.security.core.session.SessionRegistryImpl" />

<authentication-manager alias="authenticationManager">
    <authentication-provider ref="preauthAuthProvider" />
</authentication-manager>

<beans:bean id="preauthAuthProvider" 
                class="org.springframework.security.web.authentication.preauth.
                                       PreAuthenticatedAuthenticationProvider">
<beans:property name="preAuthenticatedUserDetailsService">
    <beans:bean class="com.XXX.XXXX.XXX.UserServiceImpl" />
    </beans:property>
</beans:bean>

Пожалуйста, дайте мне знать, если мне понадобится дополнительная информация.

РЕДАКТИРОВАТЬ: добавление журналов.

Для первого запроса:

2013-02-07 17: 27: 38,834 ОТЛАДКА [http-8081-2] [org.springframework.security.web.context.HttpSessionSecurityContextRepository.readSecurityContextFromSession (127)] - HttpSession в настоящее время не существует 2013-02-07 17:27: 38 834 ОТЛАДКА [http-8081-2] [org.springframework.security.web.context.HttpSessionSecurityContextRepository.loadContext (85)] - Нет SecurityContext был доступен из HttpSession: null. Будет создан новый.

Для второго запроса (обратите внимание, что детали в контексте безопасности соответствуют данным первого запроса):

2013-02-07 17: 27: 54,272 ОТЛАДКА [http-8081-2] [org.springframework.security.web.context.HttpSessionSecurityContextRepository.readSecurityContextFromSession (158)] - Получен допустимый контекст безопасности из SPRING_SECURITY_CONTEX.sramework.srameing: 'org.springframework.security.web.context.HttpSessionSecurityContextRepository.readSecurityContextFromSession (158)]. .core.context.SecurityContextImpl @ 1017293c: Аутентификация: org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken@1017293c: Субъект: org.springframework.security.core.userdetails.User6@35 -41bb-9257-b3c1acb96519; Пароль защищен]; Включено: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Полномочия: внутренние; Учетные данные: [ЗАЩИЩЕНО]; Проверено: верно; Подробности: org.springframework.security.web.authentication.WebAuthenticationDetails@ffffc434: RemoteIpAddress: 10.188.182.107; SessionId: null; Полномочия: внутренние '

Насколько я понимаю, держатель контекста безопасности хранит сведения обо всех пользователях. Но в этом случае я не могу запустить приложение из другой вкладки / браузера.


person Mahesh Kumar    schedule 07.02.2013    source источник
comment
Похоже, ваш настраиваемый фильтр проверки подлинности игнорирует изменение параметра URL-адреса, возможно, потому, что пользователь уже прошел проверку подлинности. Кроме того, вам, вероятно, следует удалить все параллельные сеансы, пока вы не научитесь правильно работать.   -  person Shaun the Sheep    schedule 07.02.2013
comment
Спасибо за ответ Люк. Проблема здесь в том, что когда запускается второй запрос, мой customAuthenticationFilter вообще не запускается. Пожалуйста, посмотрите трассировку журнала, которую я добавил к вопросу.   -  person Mahesh Kumar    schedule 07.02.2013
comment
@LukeTaylor, просто чтобы добавить сюда еще один момент .. У нас нет надлежащего механизма входа в систему. Все, что у нас есть, - это уникальная ссылка, которая исходит из URL-адреса. Так что в идеале, когда приходит второй запрос, это так же хорошо, как если бы новый пользователь пытался пройти аутентификацию. Однако контекст безопасности уже заполнен токеном первого пользователя, и на данный момент я ничего не знаю. Сейчас я пробую использовать фильтр SecurityContextPersistenceFilter. Я иду в правильном направлении?   -  person Mahesh Kumar    schedule 07.02.2013
comment
Если вы подключаетесь в одном сеансе, неудивительно, что контекст безопасности уже содержит предыдущую аутентификацию. Вам действительно следует опубликовать план вашего CustomAuthenticationFilter. Вы говорите, что это не срабатывает. Вы отлаживали его, чтобы узнать, почему? Это фильтр, поэтому его метод doFilter вызывается для каждого запроса. Поставьте там точку останова. И вы не объяснили, почему вы используете всю инфраструктуру параллельных сеансов. Кроме того, передача параметров аутентификации в URL-адресе обычно не одобряется из соображений безопасности.   -  person Shaun the Sheep    schedule 08.02.2013
comment
@LukeTaylor, я выяснил причину, по которой мой customAuthFilter не запускается для второго запроса. Похоже, что позиция, из которой я его вызываю, неверна. Я раньше использовал position = PRE_AUTH_FILTER. Я пробовал с другими позициями (например, FIRST, BASIC_AUTH_FILTER и т.д.), и фильтр может аутентифицировать несколько запросов. Однако анонимный фильтр срабатывает после моего customAuthFilter и переопределяет контекст безопасности анонимным токеном. Есть ли способ избежать этого? Теперь я пытаюсь использовать filterProxyChain, чтобы использовать только необходимые фильтры.   -  person Mahesh Kumar    schedule 08.02.2013
comment
Нет, анонимный фильтр не перезапишет контекст безопасности, если вы его уже установили.   -  person Shaun the Sheep    schedule 08.02.2013
comment
Параллельные сеансы действительно не имеют значения в моем случае, поскольку каждый запрос, поступающий из другой вкладки / браузера, будет рассматриваться как новый запрос и нигде не связан с предыдущим сеансом. Итак, я удалил всю конфигурацию, относящуюся к параллельным сеансам. А для параметров в URL-адресе каждый раз, когда пользователь пытается получить доступ к приложению, новая ссылка создается из защищенной базы данных. Эту ссылку можно использовать только один раз.   -  person Mahesh Kumar    schedule 08.02.2013


Ответы (2)


Если ваш CustomAuthenticationFilter расширяет AbstractPreAuthenticatedProcessingFilter, следующие 2 свойства могут дать вам представление. 1. checkForPrincipalChanges 2. invalidateSessionOnPrincipalChange

person Ketan    schedule 07.02.2013

Мне удалось решить эту проблему, переопределив цепочку фильтров по умолчанию (использованный прокси цепочки фильтров) и вызвав только необходимые фильтры. Спасибо Люку Тейлору и Кетану за ваши предложения. Пожалуйста, дайте мне знать, если у кого-то есть такая же проблема. Я могу опубликовать свой XML и другие материалы.

person Mahesh Kumar    schedule 18.02.2013