2013-03-04 19 views
2

我使用的是Spring MVC,並且想檢查用戶的試用期是否已過期。檢查用戶訂閱試用期是否過期使用彈簧MVC

我正在使用下面的方法

public User getUserDetail() { 
    Authentication auth = SecurityContextHolder.getContext() 
      .getAuthentication(); 
    Object principal = auth.getPrincipal(); 
     if(principal instanceof User){ 
      User user = (User) principal;    
      return user; 
     } 
     return null; 
} 

用戶對象包含時,他在第一次登錄的日期使用Spring Security的用戶詳細信息。

我檢查用下面的代碼現在

UserBean userLoggedIn = (UserBean) userService.getUserDetail(); 

    Date dt = userLoggedIn.getUserCreationDate(); 

    DateTime userCreated = new DateTime(dt).plusDays(TRIAL_PERIOD); 

    DateTime currentDateTime = new DateTime(); 


    if(currentDateTime.compareTo(userCreated) > 0 && userLoggedIn.getPackageType() == 0){ 
     return new ModelAndView("pricing","user",userLoggedIn); 
    } 

我的問題是,我不希望重複寫上面的代碼中的每個控制器的用戶訂閱。那麼有沒有什麼地方可以檢查用戶試用期是否過期,並將他重定向到定價頁面。

我有CustomUserDetail類,我從數據庫訪問用戶的詳細信息,並把它放在春季安全會議。所以我認爲這應該是檢查用戶試用期是否過期的最佳位置,但我不知道如何將用戶從此類重定向到定價頁面。

我CustomUserDetail類是

@Service 
    @Transactional(readOnly = true) 
public class CustomUserDetailsService implements UserDetailsService { 

static final Logger logger = Logger.getLogger(CustomUserDetailsService.class); 


@Resource(name="userService") 
private UserService userService; 

/* (non-Javadoc) 
* @see org.springframework.security.core.userdetails.UserDetailsService#loadUserByUsername(java.lang.String) 
*/ 
@Override 
public UserDetails loadUserByUsername(String email) 
     throws UsernameNotFoundException, DataAccessException { 
     try { 

      boolean enabled = true; 
      boolean accountNonExpired = true; 
      boolean credentialsNonExpired = true; 
      boolean accountNonLocked = true; 

      UserBean domainUser = userService.getUserByName(email);  

      domainUser.isEnabled(); 
      domainUser.isAccountNonExpired(); 
      domainUser.isCredentialsNonExpired(); 
      domainUser.isAccountNonLocked(); 


    //Collection<? extends GrantedAuthority> roles = getAuthorities((long) domainUser.getRoleId()); 

    return domainUser; 


    } catch (Exception e) { 
     logger.error("Invalid Login.",e); 
     throw new RuntimeException(e); 
    } 
} 

---更新---

我的彈簧security.xml文件是

<form-login login-page="/login.htm" 
       authentication-failure-url="/loginfailed.htm" 
       authentication-failure-handler-ref="exceptionMapper" 
       default-target-url="/index.htm" 
       always-use-default-target="true"/> 

    <access-denied-handler error-page="/logout.htm"/> 

    <logout invalidate-session="true" 
     logout-url="/logout.htm" 
     success-handler-ref="userController"/> 
<remember-me user-service-ref="customUserDetailsService" key="89dqj219dn910lsAc12" use-secure-cookie="true" token-validity-seconds="466560000"/> 
<session-management session-authentication-strategy-ref="sas"/> 
</http> 

<authentication-manager> 
     <authentication-provider user-service-ref="customUserDetailsService"> 
       <password-encoder ref="customEnocdePassword" > 
        <salt-source user-property="email"/> 
       </password-encoder> 
     </authentication-provider> 
</authentication-manager> 
<beans:bean id="customEnocdePassword" class="com.mycom.myproj.utility.CustomEnocdePassword" /> 

<beans:bean id="exceptionMapper" class="org.springframework.security.web.authentication.ExceptionMappingAuthenticationFailureHandler" > 
<beans:property name="exceptionMappings"> 
    <beans:map> 
     <beans:entry key="your.package.TrialPeriodExpiredException" value="/pricing"/> 
    </beans:map> 
</beans:property> 
</beans:bean> 

<beans:bean id="sas" 
    class="org.springframework.security.web.authentication.session.ConcurrentSessionControlStrategy"> 
<beans:constructor-arg name="sessionRegistry" ref="sessionRegistry" /> 
<beans:property name="maximumSessions" value="3" /> 

---更新----

現在我所做的是

<beans:bean id="authenticationProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider"> 
    <beans:property name="userDetailsService" ref="customUserDetailsService"/> 
    <beans:property name="passwordEncoder" ref="customEnocdePassword"/> 
    <beans:property name="preAuthenticationChecks" ref="expirationChecker"/> 
</beans:bean> 

<authentication-manager> 
    <authentication-provider user-service-ref="authenticationProvider"> 
     <password-encoder ref="customEnocdePassword" > 
       <salt-source user-property="email"/> 
     </password-encoder> 
    </authentication-provider> 
</authentication-manager> 

<!-- <authentication-manager> 
     <authentication-provider user-service-ref="customUserDetailsService"> 
       <password-encoder ref="customEnocdePassword" > 
        <salt-source user-property="email"/> 
       </password-encoder> 
     </authentication-provider> 
</authentication-manager> --> 
<beans:bean id="expirationChecker" class="com.mycom.myproj.utility.UserTrialPeriodExpirationChecker" /> 
<beans:bean id="customEnocdePassword" class="com.mycom.myproj.utility.CustomEnocdePassword" /> 

現在我得到以下錯誤

"Cannot convert value of type [org.springframework.security.authentication.dao.DaoAuthenticationProvider] 
to required type [org.springframework.security.core.userdetails.UserDetailsService] 
for property 'userDetailsService': no matching editors or conversion strategy found" 
+0

您是否考慮過將此功能添加到您的過濾器鏈中? – 2013-03-04 16:42:21

+0

用戶必須在定價頁面上進行身份驗證?如果這是真的,那麼你可以使用自定義認證成功處理程序進行重定向。 – 2013-03-04 16:57:08

+0

@Nicholas,可以請你給我一個小例子,我可以在這裏使用過濾器,因爲我試圖用戶攔截器,但是這對我沒有用。 – user965884 2013-03-04 17:28:03

回答

2

您可以設置自定義UserDetailsCheckerDaoAuthenticationProvider在驗證用戶之前驗證到期日期。

配置中的<authentication-provider>元素會生成DaoAuthenticationProvider,但該元素上沒有允許您設置其preAuthenticationChecks屬性的屬性。爲了解決此限制的命名空間配置,你將不得不回落到界定提供商作爲普通的bean:

<bean id="authenticationProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider"> 
    <property name="userDetailsService" ref="customUserDetailsService"/> 
    <property name="passwordEncoder" ref="customEnocdePassword"/> 
    <property name="preAuthenticationChecks" ref="expirationChecker"/> 
</bean> 

,並在<authentication-manager>配置是指它由ID:

<security:authentication-manager> 
    <security:authentication-provider ref="authenticationProvider"/> 
</security:authentication-manager> 

上面引用expirationChecker bean必須實現UserDetailsChecker這是一個回調接口接收的UserDetails對象,在那裏你可以拋出一個特定的異常,如果用戶的試用期已過:

public class UserTrialPeriodExpirationChecker implements UserDetailsChecker { 
    @Override 
    public void check(UserDetails user) { 
     if(/* whatever way you check expiration */) { 
      throw new TrialPeriodExpiredException(); 
     } 

     if (!user.isAccountNonLocked()) { 
      throw new LockedException("User account is locked"); 
     } 

     if (!user.isEnabled()) { 
      throw new DisabledException("User is disabled"); 
     } 

     if (!user.isAccountNonExpired()) { 
      throw new AccountExpiredException("User account has expired"); 
     } 
    } 
} 

請注意,最後三個檢查與過期檢查無關,但您必須將其放在此處,因爲默認實施(即AbstractUserDetailsAuthenticationProvider.DefaultPreAuthenticationChecks)現在已被此類覆蓋。由於默認實現是私有內部類,因此不能簡單地擴展它,但需要從那裏複製代碼以防止鎖定/禁用/等。用戶登錄。

完成所有操作後,請配置ExceptionMappingAuthenticationFailureHandler,將TrialPeriodExpiredException映射到用戶應登錄的定價頁面的URL。

<form-login authentication-failure-handler-ref="exceptionMapper" ... /> 

... 

<bean id="exceptionMapper" class="org.springframework.security.web.authentication.ExceptionMappingAuthenticationFailureHandler" > 
    <property name="exceptionMappings"> 
     <map> 
      <entry key="your.package.TrialPeriodExpiredException" value="/pricing"/> 
     </map> 
    </property> 
</bean> 
+0

嗨Zagyi,你可以請給我發送TrialPeriodExpiredException類的代碼的概述。謝謝 – user965884 2013-03-04 18:08:17

+1

這並不重要,任何'RuntimeException'的子類都可以。它唯一的用法是在'exceptionMapper'中匹配它的名字。可能從「AccountStatusException」擴展是有意義的。你可以使用它的任何子類作爲你的'TrialPeriodExpiredException'的模板。 – zagyi 2013-03-04 18:16:13

+0

嗨Zagyi,其工作正常,並將我重定向到定價頁面,但仍然有一個問題,我可以使用URL打開其他頁面,因爲domainUser對象被創建。我必須做一些用戶身份驗證。你能否向我解釋一下你想告訴我關於AbstractUserDetailsAuthenticationProvider.DefaultPreAuthenticationChecks的問題,因爲我沒有得到這部分 – user965884 2013-03-05 15:37:04

相關問題