检查用户订阅试用期是否过期使用弹簧MVC
我使用的是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"
您可以设置自定义UserDetailsChecker
上DaoAuthenticationProvider
在验证用户之前验证到期日期。
配置中的<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>
嗨Zagyi,你可以请给我发送TrialPeriodExpiredException类的代码的概述。谢谢 – user965884 2013-03-04 18:08:17
这并不重要,任何'RuntimeException'的子类都可以。它唯一的用法是在'exceptionMapper'中匹配它的名字。可能从“AccountStatusException”扩展是有意义的。你可以使用它的任何子类作为你的'TrialPeriodExpiredException'的模板。 – zagyi 2013-03-04 18:16:13
嗨Zagyi,其工作正常,并将我重定向到定价页面,但仍然有一个问题,我可以使用URL打开其他页面,因为domainUser对象被创建。我必须做一些用户身份验证。你能否向我解释一下你想告诉我关于AbstractUserDetailsAuthenticationProvider.DefaultPreAuthenticationChecks的问题,因为我没有得到这部分 – user965884 2013-03-05 15:37:04
您是否考虑过将此功能添加到您的过滤器链中? – 2013-03-04 16:42:21
用户必须在定价页面上进行身份验证?如果这是真的,那么你可以使用自定义认证成功处理程序进行重定向。 – 2013-03-04 16:57:08
@Nicholas,可以请你给我一个小例子,我可以在这里使用过滤器,因为我试图用户拦截器,但是这对我没有用。 – user965884 2013-03-04 17:28:03