假设您有一个正在运行的能够禁用用户的 Web 应用程序,我将向您展示如何在运行时锁定这些用户。
基本思想是使用刷新的用户详细信息重新验证每个请求。为此,您需要一个自定义的SecurityContextRepository
丢弃保存在 http 会话中的用户详细信息。
public class RefreshingUserDetailsSecurityContextRepository implements SecurityContextRepository {
private final SecurityContextRepository delegate;
private final UserDetailsService userDetailsService;
public RefreshingUserDetailsSecurityContextRepository(final SecurityContextRepository delegate, final UserDetailsService userDetailsService) {
Assert.notNull(delegate);
Assert.notNull(userDetailsService);
this.delegate = delegate;
this.userDetailsService = userDetailsService;
}
@Override
public SecurityContext loadContext(final HttpRequestResponseHolder requestResponseHolder) {
SecurityContext securityContext = delegate.loadContext(requestResponseHolder);
if(securityContext.getAuthentication() == null) {
return securityContext;
}
Authentication principal = securityContext.getAuthentication();
UserDetails userDetails = userDetailsService.loadUserByUsername(principal.getName());
//this code has to be modified when using remember me service, jaas or a custom authentication token
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(userDetails, userDetails.getPassword());
securityContext.setAuthentication(token);
saveContext(securityContext, requestResponseHolder.getRequest(), requestResponseHolder.getResponse());
return securityContext;
}
@Override
public void saveContext(final SecurityContext context, final HttpServletRequest request, final HttpServletResponse response) {
delegate.saveContext(context, request, response);
}
@Override
public boolean containsContext(final HttpServletRequest request) {
return delegate.containsContext(request);
}
}
RefreshingUserDetailsSecurityContextRepository 简单地包装了默认的SecurityContextRepository,即HttpSessionSecurityContextRepository。因此,您无需担心会话超时或自己存储SecurityContext。在loadContext 方法中,用户详细信息会使用userDetailsService 刷新,并在将其分发给调用者之前写回SecurityContext。
不要将用户 authorities 传递给 UsernamePasswordAuthenticationToken 构造函数。否则令牌被标记为已验证,并且重新验证永远不会触发!
请注意 RefreshingUserDetailsSecurityContextRepository 将您限制为 UsernamePasswordAuthenticationToken。例如,如果您想使用 Jaas、Spring Security 记住我或不是从 UsernamePasswordAuthenticationToken 派生的自定义身份验证令牌,您需要调整 RefreshingUserDetailsSecurityContextRepository 以适应您的需求。
将RefreshingUserDetailsSecurityContextRepository 添加到您的安全配置中。
<security:http use-expressions="true" security-context-repository-ref="refreshingUserDetailsSecurityContextRepository">
<security:intercept-url ... />
<security:form-login ... />
<security:logout />
</security:http>
<bean id="refreshingUserDetailsSecurityContextRepository" class="security.RefreshingUserDetailsSecurityContextRepository">
<constructor-arg index="0">
<bean class="org.springframework.security.web.context.HttpSessionSecurityContextRepository" />
</constructor-arg>
<constructor-arg index="1" ref="userDetailsService" />
</bean>
就是这样。您已登录但已禁用的用户会在其下一页请求时被重定向回登录页面。
这是一个功能齐全的example。