#java #spring #spring-mvc #spring-security
#java #spring #spring-mvc #spring-безопасность
Вопрос:
Я настроил Spring Security для правильного перехвата и запроса пользователя на пользовательскую страницу входа, которая затем проходит правильную аутентификацию и добавляет пользовательские данные в SecurityContextHolder.
В дополнение к этому я теперь хочу добавить свой собственный пользовательский объект User, добавляемый в сеанс при каждом входе в систему; таким образом, код будет выглядеть следующим образом:
public returnwhat? doMySupplementaryLogin() {
UserDetails principal = (UserDetails) SecurityContextHolder.getContext()
.getAuthentication().getPrincipal();
MyUser user = myUserService.getMyUser(principal.getUsername());
add user to what ?
}
Куда пойдет этот код? Я хочу, чтобы была выполнена аутентификация nomral spring, а затем приведенный выше код поместит объект MyUser в сеанс, а затем отправит пользователя на исходный перехваченный URL / viewname. У меня сильное чувство, что я усложняю ситуацию больше, чем нужно…
Ответ №1:
Вы действительно усложняете … 🙂
Что вы хотите, так это добавить пользовательского поставщика аутентификации в обычный менеджер аутентификации Spring. Итак, вы бы настроили менеджер аутентификации следующим образом:
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider user-service-ref="authServiceImpl">
<security:password-encoder ref="passwordEncoder"/>
</security:authentication-provider>
</security:authentication-manager>
<bean id="passwordEncoder" class="org.springframework.security.authentication.encoding.Md5PasswordEncoder"/>
Теперь вам нужно только определить компонент authServiceImpl внутри вашего контекста spring. Вы можете сделать это с помощью xml или аннотаций (мой предпочтительный способ).
@Service
public class AuthServiceImpl implements AuthService {
Вам необходимо реализовать интерфейс AuthService. Просто реализуйте методы из интерфейса — должно быть довольно просто.
Вам не нужно помещать данные в SecurityContextHolder самостоятельно — spring сделает это.
Чего вы хотите, так это:
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException {
return MyUser user = myUserService.getMyUser(username);
}
Не стесняйтесь спрашивать, есть ли у вас какие-либо дополнительные вопросы.
РЕДАКТИРОВАТЬ: Или вы могли бы просто использовать свой класс UserService для реализации интерфейса — я просто сделал это так, потому что вы не предоставили свой класс UserService.
Комментарии:
1. спасибо, хорошо, как мне получить доступ к MyUser (который реализует UserDetails) в контроллере? А «Authservice» — это опечатка и должно быть «UserDetailsService»?
2. Извините, это не опечатка. На самом деле у меня есть другой интерфейс в моем authserviceimpl. AuthService действительно расширяет UserDetailsService.
3. Вы можете получить доступ к своему классу MyUser в своем контроллере, как и с любым другим компонентом Spring. автоматическое подключение или настройка в вашем applicationContext.xml
4. Как и любой другой компонент Spring? Но разве это не атрибут сеанса / в контексте безопасности? Я добиваюсь прогресса, как получить доступ к объекту MyUser из jsp (например, для отображения приветствуемого имени пользователя)?
5. Вам вообще не нужно обращаться к объекту User — вы можете получить доступ к UserPrincipal (объекту UserDetails, который вы вернули в методе loadUserByUsername), хотя:
${pageContext.request.userPrincipal.name}
распечатает текущее имя пользователя, вошедшее в систему
Ответ №2:
или добавьте свой собственный AuthenticationSuccessHandler, например, этот класс, который я добавил, чтобы я мог хранить имя пользователя и пароль в сеансе, чтобы я мог входить в другие микросервисы, когда это необходимо:
public class AuthenticationSuccessWithSessionHandler extends SavedRequestAwareAuthenticationSuccessHandler implements AuthenticationSuccessHandler, LogoutSuccessHandler {
public static final String USERNAME = "username";
public static final String PASSWORD = "password";
@Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
request.getSession().removeAttribute(USERNAME);
request.getSession().removeAttribute(PASSWORD);
}
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
super.onAuthenticationSuccess(request, response, authentication);
request.getSession().setAttribute(PASSWORD, request.getParameter(PASSWORD));
request.getSession().setAttribute(USERNAME, request.getParameter(USERNAME));
}
}
и зарегистрировал его
AuthenticationSuccessWithSessionHandler successHandler = new AuthenticationSuccessWithSessionHandler();
http.authorizeRequests().antMatchers("/login", "/logout", "/images", "/js").permitAll().antMatchers("/feeds/**")
.authenticated().and().formLogin()
.successHandler(successHandler)
.and().logout().logoutUrl("/logout").logoutSuccessHandler(successHandler).logoutSuccessUrl("/login");
обратите внимание, что extends SavedRequestAwareAuthenticationSuccessHandler сохраняет исходный URL-адрес и восстанавливает его после успешного входа в систему.