Spring Security 3.1 и возврат анонимных сведений о пользователе

Я пытаюсь понять, как заставить Spring Security вернуть объект UserDetails для анонимных пользователей для этого вызова:

SecurityContextHolder.getContext().getAuthentication().getPrincipal()

Я знаю, что без специальной настройки этот вызов вернет строку вместо объекта UserDetails, который вы создаете с помощью пользовательской реализации UserDetailsService, но я бы не хотел постоянно везде проверять «if (основной экземпляр строки)». Есть ли способ сделать это с конфигурацией Spring - способ, который будет хранить анонимный объект UserDetails в контексте сеанса пользователя до тех пор, пока он не войдет в систему? Якобы мне нужны уникальные анонимные сведения о пользователе для каждого гостя, чтобы я мог отслеживать их индивидуальное использование.

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

@RequestMapping(value = "/almanac/new", method = RequestMethod.GET)
@PreAuthorize("hasRole('ROLE_ADMIN')")
public String newSetup(ModelMap model) {

Вот мой контекст безопасности spring (полный, за исключением вложенного узла bean-компонентов). Вы можете заметить, что я пытался включить "анонимный"

<debug />
<http pattern="/js/**"  security="none" />
<http pattern="/css/**"  security="none" />
<http pattern="/images/**"  security="none" />
<http pattern="/loggedout.jsp" security="none"/>
<http name="httpSiteMap" use-expressions="true">
    <custom-filter ref="almanacUsrPwdAuthProcFilter" before="FORM_LOGIN_FILTER"/>
    <intercept-url pattern="/login*" access="isAnonymous()" />
    <intercept-url pattern="/home/**" access="hasRole('ROLE_USER')" />
    <intercept-url pattern="/admin/**" access="hasRole('ROLE_ADMIN')" />
    <intercept-url pattern="/**" access="isAnonymous()" />
    <form-login  login-page="/login.jsp"
                 default-target-url="/home.htm"
                 always-use-default-target="false" />
    <logout logout-success-url="/loggedout.jsp" delete-cookies="JSESSIONID"/>
    <session-management invalid-session-url="/timeout.jsp">
        <concurrency-control max-sessions="1" error-if-maximum-exceeded="true" />
    </session-management>
    <anonymous enabled="true" />
</http>

<global-method-security pre-post-annotations="enabled" secured-annotations="enabled" />

<authentication-manager alias="mainAuthMgr">
    <authentication-provider ref="almanacAuthenticationProvider"/>
</authentication-manager>

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


person ogradyjd    schedule 29.01.2012    source источник
comment
Не могли бы вы объяснить, для чего вы хотите использовать анонимный UserDetails? Какие данные он будет содержать и как вы будете его использовать? Вам не нужно <anonymous enabled="true" />, так как это значение по умолчанию. Вы должны увидеть AnonymousAuthenticationFilter в журнале отладки в качестве подтверждения.   -  person Shaun the Sheep    schedule 29.01.2012
comment
Я пытаюсь избежать того, чтобы вызов getPrincipal() возвращал строку. Я бы хотел, чтобы этот вызов возвращал только реализацию UserDetails, независимо от того, аутентифицируется ли spring анонимно или пользователь входит в систему. Я хочу избежать проверки возвращаемого значения getPrincipal() для instanceof String. Конечно, поскольку документация в некоторых областях очень неоднозначна, а информация по конкретным точкам конфигурации разбросана по многим главам, трудно понять, следует ли вам это делать или просто иметь дело со сравнениями instanceof.   -  person ogradyjd    schedule 29.01.2012


Ответы (1)


Вы действительно не дали подробностей о том, какие данные вы хотите извлечь из UserDetails для анонимного пользователя. Если вы просто хотите проверить имя пользователя, вы можете использовать Authentication.getName().

В любом случае, если вам нужен более подробный доступ к контексту безопасности, рекомендуется использовать настраиваемый интерфейс для отделения кода вашего приложения от классов безопасности Spring (см. мой ответ об использовании средства доступа к контексту безопасности). Таким образом, вы должны проверять тип принципала только в одном месте, а не повторять проверку «везде», где вы хотите получить доступ к пользовательским данным.

Если вы абсолютно хотите всегда иметь один и тот же основной тип в объекте аутентификации, независимо от того, является ли пользователь анонимным, вам придется отключить анонимную аутентификацию через пространство имен и добавить настраиваемый фильтр для выполнения задания на основе существующего AnonymousAuthenticationFilter .

person Shaun the Sheep    schedule 29.01.2012
comment
Должно быть, я неправильно понимаю что-то очень простое, если мне не нужно делать то, что вы сказали, потому что безопасность метода не работает с анонимной аутентификацией по умолчанию. Вы можете видеть из моего кода, что я включил глобальную безопасность метода, и все же я могу запросить URL-адрес, который вызывает метод newSetup без входа в систему, и я почти уверен, что нигде не указывал, что анонимные пользователи должны иметь ROLE_ADMIN (не не знаю, как бы, если бы я хотел прямо сейчас). Я реализую фасад доступа к безопасности, как вы предложили. - person ogradyjd; 30.01.2012
comment
Из второй части вашего вопроса неясно, как это связано с анонимной аутентификацией или необходимостью доступа к контексту безопасности. Работает ли вообще аннотация для неанонимных пользователей? Если нет, вероятно, это проблема видимости контекста приложения — см. эти часто задаваемые вопросы . - person Shaun the Sheep; 30.01.2012
comment
В этом вопросе также обсуждается проблема использования аннотаций безопасности с контроллерами MVC. - person Shaun the Sheep; 30.01.2012
comment
Не обращайте внимания на проблему PreAuthorize. Оказывается, это не имеет ничего общего с анонимным входом в систему и связано с вуду иерархии контекста приложения Spring. Точное описание и решение этой проблемы: здесь - person ogradyjd; 30.01.2012
comment
...и да, Люк, ты был абсолютно прав. Спасибо за подсказку, которая привела меня к FAQ и исправлению. - person ogradyjd; 30.01.2012