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;
  }
}