У меня есть веб-приложение Spring MVC, которое использует Spring Security. Я хочу знать имя пользователя, вошедшего в систему. Я использую фрагмент кода, приведенный ниже. Это принятый способ?
Мне не нравится иметь вызов статического метода внутри этого контроллера - это противоречит всей цели Spring, ИМХО. Есть ли способ настроить приложение, чтобы вместо него вводили текущий SecurityContext или текущую аутентификацию?
@RequestMapping(method = RequestMethod.GET)
public ModelAndView showResults(final HttpServletRequest request...) {
final String currentUser = SecurityContextHolder.getContext().getAuthentication().getName();
...
}
java
spring
spring-mvc
spring-security
Скотт Бэйл
источник
источник
Ответы:
Если вы используете Spring 3 , самый простой способ:
источник
С тех пор, как на этот вопрос был дан ответ, многое изменилось в мире весны. Spring упростил получение текущего пользователя в контроллере. Для других bean-компонентов Spring принял предложения автора и упростил внедрение SecurityContextHolder. Более подробная информация в комментариях.
Это решение, с которым я в конечном итоге пошел. Вместо того, чтобы использовать
SecurityContextHolder
в моем контроллере, я хочу внедрить что-то, что используетSecurityContextHolder
скрытно, но абстрагирует этот синглтоноподобный класс от моего кода. Я не нашел другого способа сделать это, кроме как развернуть свой собственный интерфейс, вот так:Теперь мой контроллер (или любой другой POJO) будет выглядеть так:
И, поскольку интерфейс является точкой развязки, модульное тестирование является простым. В этом примере я использую Mockito:
Реализация интерфейса по умолчанию выглядит следующим образом:
И, наконец, рабочий конфигурационный Spring выглядит так:
Более чем глупым кажется то, что Spring, контейнер для инъекций зависимостей, не предоставил способ внедрить нечто подобное. Я понимаю, что
SecurityContextHolder
унаследовал от acegi, но все же. Дело в том, что они так близки - если бы уSecurityContextHolder
них был только геттер для получения базовогоSecurityContextHolderStrategy
экземпляра (который является интерфейсом), вы могли бы внедрить его. На самом деле, я даже открыл проблему Jira на этот счет.И последнее: я просто существенно изменил ответ, который у меня был здесь раньше. Проверьте историю, если вам интересно, но, как указал мне коллега, мой предыдущий ответ не будет работать в многопоточной среде. По умолчанию
SecurityContextHolderStrategy
используется базовыйSecurityContextHolder
экземплярThreadLocalSecurityContextHolderStrategy
, который хранитSecurityContext
s вThreadLocal
. Следовательно, не обязательно хорошая идея вставлятьSecurityContext
объект непосредственно в bean-компонент во время инициализации - его может потребоваться извлекатьThreadLocal
каждый раз, в многопоточной среде, так что получается правильный.источник
Я согласен с тем, что необходимость запрашивать SecurityContext для текущего пользователя воняет, кажется, что это не совсем Spring способ справиться с этой проблемой.
Я написал статический «вспомогательный» класс для решения этой проблемы; он грязный в том смысле, что это глобальный и статический метод, но я решил, что если мы изменим что-либо, связанное с безопасностью, по крайней мере, мне нужно изменить детали только в одном месте:
источник
Чтобы это просто отображалось на ваших страницах JSP, вы можете использовать Spring Security Tag Lib:
http://static.springsource.org/spring-security/site/docs/3.0.x/reference/taglibs.html
Чтобы использовать любой из тегов, у вас должен быть тег безопасности liblib, объявленный в вашем JSP:
Затем на странице JSP сделать что-то вроде этого:
ПРИМЕЧАНИЕ. Как уже упоминалось в комментариях @ SBerg413, вам необходимо добавить
для тега "http" в конфигурации security.xml, чтобы это работало.
источник
Если вы используете Spring Security ver> = 3.2, вы можете использовать
@AuthenticationPrincipal
аннотацию:Здесь
CustomUser
пользовательский объект, который реализует,UserDetails
который возвращается пользовательскимUserDetailsService
.Дополнительную информацию можно найти в главе @AuthenticationPrincipal справочных документов Spring Security.
источник
Я получаю аутентифицированного пользователя по HttpServletRequest.getUserPrincipal ();
Пример:
источник
null
если пользователь аутентифицирован анонимно (http
>anonymous
элементы в Spring Security XML).SecurityContextHolder
илиSecurityContextHolderStrategy
это правильный путь.В Spring 3+ у вас есть следующие варианты.
Опция 1 :
Вариант 2:
Вариант 3:
Вариант 4: Необычный: Проверьте это для более подробной информации
источник
@CurrentUser
версии 3.2 поставляется Spring-security-web, который работает как пользовательский@ActiveUser
по вашей ссылке.@AuthenticationPrincipal
с пользовательской@CurrentUser
аннотацией. Начиная с версии 3.2 нам не нужно реализовывать пользовательский преобразователь аргументов, как в связанном ответе. Этот другой ответ более подробно.Да, статика, как правило, плохая, как правило, но в этом случае статика - самый безопасный код, который вы можете написать. Поскольку контекст безопасности связывает принципала с текущим работающим потоком, наиболее безопасный код будет обращаться к статическому потоку из потока как можно напрямую. Скрытие доступа за внедренным классом-оболочкой дает злоумышленнику больше очков для атаки. Им не понадобится доступ к коду (который им будет сложно изменить, если jar был подписан), им просто нужен способ переопределить конфигурацию, что можно сделать во время выполнения или вставить какой-то XML в путь к классам. Даже использование внедрения аннотаций в подписанном коде может быть заменено внешним XML. Такой XML мог бы внедрить работающую систему с мошенническим принципалом.
источник
Я бы просто сделал это:
источник
SecurityContextHolderAwareRequestFilter
который обертывает запрос и реализует этот вызов путем доступа кSecurityContextHolder
.Для последнего приложения Spring MVC, которое я написал, я не вставлял держатель SecurityContext, но у меня был базовый контроллер, у меня было два вспомогательных метода, связанных с этим ... isAuthenticated () и getUsername (). Внутренне они делают вызов статического метода, который вы описали.
По крайней мере, тогда это только в одном месте, если вам нужно позже рефакторинг.
источник
Вы можете использовать Spring AOP. Например, если у вас есть какой-то сервис, он должен знать текущий принципал. Вы можете ввести пользовательскую аннотацию, т. Е. @Principal, которая указывает, что эта служба должна быть главной зависимой.
Затем в своем совете, который, по моему мнению, должен расширять MethodBeforeAdvice, убедитесь, что конкретный сервис имеет аннотацию @Principal, и введите имя Принципала или установите для него значение «ANONYMOUS».
источник
Единственная проблема заключается в том, что даже после аутентификации в Spring Security пользовательский / основной компонент не существует в контейнере, поэтому внедрение через зависимости будет затруднено. Перед тем, как использовать Spring Security, мы должны создать bean-объект в области сеанса с текущим принципалом, внедрить его в «AuthService», а затем внедрить этот сервис в большинство других сервисов в приложении. Таким образом, эти службы просто вызовут authService.getCurrentUser () для получения объекта. Если в вашем коде есть место, где вы получаете ссылку на того же принципала в сеансе, вы можете просто установить его в качестве свойства для вашего bean-объекта в области сеанса.
источник
Попробуй это
источник
Лучшее решение, если вы используете Spring 3 и вам нужен аутентифицированный принципал в вашем контроллере, это сделать что-то вроде этого:
источник
Я использую
@AuthenticationPrincipal
аннотацию в@Controller
классах, а также в@ControllerAdvicer
аннотированных. Напр .:Где
UserActive
это класс я использую для зарегистрированных пользователей услуг, и простирается отorg.springframework.security.core.userdetails.User
. Что-то вроде:Действительно легко.
источник
Определите
Principal
как зависимость в вашем методе контроллера, и Spring вызовет текущего аутентифицированного пользователя в вашем методе при вызове.источник
Я хотел бы поделиться своим способом поддержки пользовательских данных на странице бесплатного маркера. Все очень просто и работает отлично!
Вам просто нужно разместить запрос на аутентификацию
default-target-url
(страница после входа в форму). Это мой метод Controler для этой страницы:И это мой код ftl:
И все, имя пользователя будет появляться на каждой странице после авторизации.
источник