Spring Защищенный пользовательский фильтр (сменить пароль)
Я использую Spring Безопасность для защиты HTTP-запросов на веб-сайте. Основное использование заключается в защите страниц, чтобы пользователь перенаправлялся на страницу входа при попытке доступа к этим страницам.
Однако у меня есть еще одно требование. В моей модели я могу указать пароль пользователя как временный, так что при успешном входе в систему они должны автоматически принудительно менять свой пароль. После изменения пароля они должны быть отправлены на страницу, с которой они первоначально пытались получить доступ.
Кто-нибудь использовал Spring Security для этой цели? Нужно ли создавать собственный фильтр?
Спасибо,
Эндрю
Ответы
Ответ 1
В Spring Security 3.0 вы можете реализовать пользовательский AuthenticationSuccessHandler
.
В этом обработчике вы можете перенаправить пользователя с временным паролем на страницу смены пароля вместо первоначально запрошенной страницы. После изменения пароля вы можете перенаправить пользователя на первоначально запрошенную страницу, используя SavedRequestAwareAuthenticationSuccessHandler
, которая является реализацией обработчика по умолчанию.
public class MyHandler implements AuthenticationSuccessHandler {
private AuthenticationSuccessHandler target = new SavedRequestAwareAuthenticationSuccessHandler();
public void onAuthenticationSuccess(HttpServletRequest request,
HttpServletResponse response, Authentication auth) {
if (hasTemporaryPassword(auth)) {
response.sendRedirect("/changePassword");
} else {
target.onAuthenticationSuccess(request, response, auth);
}
}
public void proceed(HttpServletRequest request,
HttpServletResponse response, Authentication auth) {
target.onAuthenticationSuccess(request, response, auth);
}
}
@Controller("/changePassword")
public class ChangePasswordController {
@Autowired
private MyHandler handler;
@RequestMapping(method = POST)
public void changePassword(HttpServletRequest request,
HttpServletResponse response,
@RequestParam(name = "newPassword") String newPassword) {
// handle password change
...
// proceed to the secured page
handler.proceed(request, response, auth);
}
// form display method, etc
...
}
Ответ 2
Немного поздно, но, надеюсь, это может помочь другим найти эту ссылку. Если вы используете пользовательский UserDetailsService, вы можете установить учетные данные объекта UserNonExpired на false, например, чтобы не разрешать доступ к любому защищенному контенту, пока это поле не вернется к истинному.
В принципе, когда у вас есть срок действия пароля, вы установите поле в своей модели пользователя (возможно, passwordExpired), и когда пользователь UserDetailsService вытащит пользователя, ваш UserDetailsService будет использовать это значение для установки учетных данныхNonExpired.
Затем все, что вам нужно сделать, это добавить некоторую конфигурацию в ваш applicationContext-security.xml для настройки сопоставлений исключений аутентификации. Это позволит вам поймать исключение, занесенное с истекшими учетными данными, и заставить пользователя перейти на страницу пароля reset. Вы можете дополнительно заблокировать заблокированные и отключенные учетные записи, используя аналогичный метод. Пример конфигурации приведен ниже:
ApplicationContext-security.xml
<beans:bean id="exceptionTranslationFilter" class="org.springframework.security.web.authentication.ExceptionMappingAuthenticationFailureHandler">
<beans:property name="exceptionMappings">
<beans:props>
<beans:prop key="org.springframework.security.authentication.BadCredentialsException">/login_error</beans:prop>
<beans:prop key="org.springframework.security.authentication.CredentialsExpiredException">/password_expired</beans:prop>
<beans:prop key="org.springframework.security.authentication.LockedException">/locked</beans:prop>
<beans:prop key="org.springframework.secuirty.authentication.DisabledException">/disabled</beans:prop>
</beans:props>
</beans:property>
</beans:bean>
<http use-expressions="true">
<!-- ADD BLACKLIST/WHITELIST URL MAPPING -->
<form-login login-page="/login" default-target-url="/" authentication-failure-handler-ref="exceptionTranslationFilter" />
</http>
Затем просто убедитесь, что вы настроили свои контроллеры для обслуживания этих ссылок с соответствующим контентом.
Ответ 3
Да, я сделал это с фильтром ForceChangePasswordFilter. Потому что, если пользователь вводит URL вручную, он может обходить форму пароля изменения. С фильтром запрос всегда перехватывается.
Ответ 4
Очень полезная форма ответа jyore, это именно то, что я искал. Если вы используете пользовательский класс, реализующий UserDetailsService
, вы можете сделать это как следующее вместе с приведенным выше определением bean в applicationContext.xml
. Одно дело, что на основе вашего заголовка CML вам может понадобиться использовать <bean ....
или <prop ...
вместо <beans:bean ...
или <beans:prop ...
import ......
@Service("userService")
public class UserDetailsServiceImpl implements UserDetailsService {
private static Logger logger = LoggerFactory
.getLogger(UserDetailsServiceImpl.class);
@Autowired
private UserDao userDao;
@Override
public UserDetails loadUserByUsername( String username )
throws UsernameNotFoundException, DataAccessException , CredentialsExpiredException ,BadCredentialsException ,
LockedException , DisabledException , UsernameNotFoundException
{
User user = userDao.getUserByUsername( username );
System.out.println("User Found");
if( user == null ){
// System.out.println("User Not Found");
logger.error( "User Not Found");
throw new UsernameNotFoundException( username + " is not found." );
}
if( user.isEnabled() == false ){
// System.out.println("User not enabled");
logger.error( "User not enabled");
throw new DisabledException( "User not enabled" );
}
if( user.isLocked() == true ){
//System.out.println("User is Locked");
logger.error( "User is Locked");
throw new LockedException( "User is Locked" );
}
if( user.isPasswordExpired() == true ){
// System.out.println("Password Expired");
logger.error( "Password Expired");
throw new CredentialsExpiredException( "Password Expired" );
}
return user;
}
}