2010-07-26 74 views
14

我使用Spring Security來保護到網站的HTTP請求。主要用於保護頁面,以便在嘗試訪問這些頁面時將用戶重定向到登錄頁面。Spring Security自定義篩選器(更改密碼)

但是,我有進一步的要求。在我的模型中,我可以將用戶的密碼標記爲臨時密碼,以便當它們成功登錄時,它們應該被自動強制更改密碼。一旦密碼被改變,它們應該被轉發到他們最初嘗試訪問的頁面上。

有沒有人爲此使用Spring Security?我是否需要創建自己的自定義過濾器?

感謝,

安德魯

回答

18

在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 
    ... 
} 
+0

感謝。我可以很容易地完成第一部分,但不確定「將用戶重定向到...使用SavedRequestAwareAuthenticationSuccessHandler」的含義。我如何重定向到一個處理程序? – DrewEaster 2010-07-26 15:35:00

+0

@dewzilla:我添加了它的樣子(使用Spring MVC控制器進行密碼更改,未經測試)。 – axtavt 2010-07-26 16:49:05

+2

事實上,在認證成功處理程序中檢查密碼到期是違反直覺的,不是嗎?如果密碼過期,您應該無法進行身份驗證。檢查@jyore提供的答案。 – Octavian 2013-04-30 10:26:14

6

是的,我用過濾器ForceChangePasswordFilter做了這個。因爲如果用戶手動鍵入網址,他們可以繞過更改密碼錶單。通過篩選器,請求總是被攔截。

+0

你會關心分享你的代碼嗎? – Jonathan 2013-07-24 08:52:45

+1

喬納森,那是多年前,我現在無法訪問該代碼。 – rodrigoap 2013-07-24 15:24:10

+0

rodrigoap我明白。我分享同樣的觀點,如果你使用成功處理程序,用戶仍然可以通過直接在地址欄中寫入URL來訪問其他頁面。但基本上,你能分享至少過濾器內的意圖嗎?我試圖在過濾器中有一個重定向,它會導致一個無限的重定向循環,正如這裏所提到的:http://stackoverflow.com/questions/3954930/spring-security-3-0-how-do-i-specify-urls -to-其-A-自定義過濾器適用。將在SO中發佈一個單獨的問題。 – Jonathan 2013-07-25 03:43:06

13

有點晚了,但希望這可以幫助別人找到這個鏈接。如果您使用自定義的UserDetailsS​​ervice,則可以將User對象的credentialsNonExpired設置爲false,例如,在該字段設置爲true之前,不允許訪問任何安全內容。

基本上,當你有密碼到期時,你將在你的用戶模型(passwordExpired也許)中設置一個字段,當你的UserDetailsS​​ervice提取用戶時,你的UserDetailsS​​ervice將使用該值來設置credentialsNonExpired。

然後,您需要做的就是將一些配置添加到您的applicationContext-security.xml以設置驗證異常映射。這將允許您捕獲過期憑據引發的異常,並強制用戶重置密碼頁面。您還可以使用類似的方法捕獲鎖定和禁用的帳戶。該配置示例如下所示:

的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> 

然後,只需確保你有你的控制器設置服務與適當的內容這些鏈接。

+2

此解決方案有一個缺點,即在用戶通過身份驗證之前已檢查用戶憑證NonExpired,因此您發現用戶憑證是過期給未經認證的用戶(例如攻擊者)。我想這樣的信息並不那麼重要,但我仍然發現rodrigoap解決方案更好。 – 2014-04-30 08:49:25

3

非常有用的答案表格jyore,這正是我一直在尋找的。如果您正在使用實現UserDetailsService的自定義類,則可以在applicationContext.xml中將上述bean定義與以上bean定義一起使用。一件事是,根據您的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; 
    } 
} 
+0

問題是在檢查密碼之前調用UserDetailsS​​ervice。 – 2017-05-29 14:55:06