2013-01-13 1 views
13

스프링 보안을 사용하여 비밀번호 변경 기능을 구현했지만 ((UserDetails) principal) .getPassword())는 로그인 한 사용자에 대해 null을 반환합니다.UserDetails getPassword는 봄 보안 3.1에서 null을 반환합니다. 현재 로그인 한 사용자의 비밀번호를 얻는 방법은 무엇입니까?

올바르게 기억하면 이전 버전 3.0에서 사용되었습니다. 3.1에서 변경 되었기 때문에 로그인 한 사용자의 현재 암호를 검색 할 수 없습니까?

아래 코드에서 웹 페이지에서 사용자 비밀번호에 입력 한 현재 비밀번호를 확인하고 있습니다. 그런 다음 로그인 한 사용자의 비밀번호가 입력 한 비밀번호와 일치하는지 확인합니다. 그렇다면 oldPasswordMatchNewPassword = true로 설정하고 싶습니다.

이 기능을 어떻게 구현합니까?

@RequestMapping(value = "/account/changePassword.do", method = RequestMethod.POST) 
    public String submitChangePasswordPage(
      @RequestParam("oldpassword") String oldPassword, 
      @RequestParam("password") String newPassword) { 
     Object principal = SecurityContextHolder.getContext() 
       .getAuthentication().getPrincipal(); 
     String username = principal.toString(); 
     if (principal instanceof UserDetails) { 
      username = ((UserDetails) principal).getUsername(); 
      System.out.println("username: " + username); 
      System.out.println("password: " 
        + ((UserDetails) principal).getPassword()); 
      if (((UserDetails) principal).getPassword() != null) { 
       if (((UserDetails) principal).getPassword().equals(oldPassword)) { 
        oldPasswordMatchNewPassword = true; 
       } 
      } 
     } 
    if (oldPasswordMatchNewPassword == true) { 
     logger.info("Old password matches new password. Password will be updated."); 
     changePasswordDao.changePassword(username, newPassword); 
     SecurityContextHolder.clearContext(); 
     return "redirect:home.do"; 
    } else { 
     logger.info("Old password did not match new password. Password will be not be updated."); 
     return null; 
    } 
} 

리턴 된 값을 볼 수 있도록 두 개의 sysout()을 넣었습니다. ((UserDetails) principal) .getUsername() 올바른 로그인 사용자를 볼 수 있습니다. ((UserDetails) principal) .getPassword() null을 반환합니다.

어떻게 ((UserDetails) 주체) .getPassword()이 값을 얻습니까?

미리 감사드립니다.

답변

25

이 문제를 해결하기 위해이 코드 블록 (erase-credentials = "false")을 사용했습니다. 명시 적으로해야 사용자가 (일반적으로 좋은 일이) 인증 된 후 암호를 메모리에 저장되지 않기 때문에

<authentication-manager alias="authenticationManager" erase-credentials="false"> 
    <!-- authentication-provider user-service-ref="userService" --> 
    <authentication-provider> 
     <jdbc-user-service data-source-ref="dataSource" /> 
    </authentication-provider> 
</authentication-manager> 
6

예, 버전 3.1에서 변경되었습니다. 자격 증명은 성공적인 인증 후에 기본적으로 지워집니다. 이를 방지하려면 ProviderManager에서 eraseCredentialsAfterAuthentication을 false로 설정할 수 있습니다. 세부 정보보기 : http://static.springsource.org/spring-security/site/docs/3.2.x/reference/core-services.html#core-services-erasing-credentials

+0

그건 의미가 있습니다. 이렇게하는 가장 좋은 방법은 무엇입니까? eraseCredentialsAfterAuthentication을 보안 위험을 초래할 수 있으므로 해제하고 싶지 않습니다. 이걸 알아내는 걸 도와 주실 수 있습니까? – texasdude11

2

:이 우아한 솔루션입니다 나도 몰라하지만 그것은 내 문제를 해결 그것을 사용하기 위해 다시 적재하십시오.

String name = SecurityContextHolder.getContext().getAuthentication(); 

try { 
    authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(name, oldPassword)); 
    // Update password here with your dao 
} catch (AuthenticationException e) { 
    // Old password was wrong 
} 

당신이 암호로 인코딩 전략 같은 것들에 대해 걱정할 필요가 없습니다 그 방법 : 대안과보다 유연한 전략은 AuthenticationManager의 인스턴스를 주입하고 직접 그것을 사용하는 것입니다. 암호를 일반 텍스트로 저장해서는 안됩니다. 그들은 bcrypt or something similar을 사용하여 해시되어야합니다.

관련 문제