【问题标题】:Spring Security logoff a user while runtimeSpring Security 在运行时注销用户
【发布时间】:2014-12-11 04:15:50
【问题描述】:

我正在实现一个基于 Spring 的 Web 应用程序,它使用 Spring Security 和 DaoAuthenticationProvider。因此,我创建了一个具有布尔 isEnabled(); 方法的 User 类,因为它实现了 Springs UserDetails 接口。因此,如果用户“未启用”,则该用户将无法再登录。到目前为止一切顺利。

如果我在运行时禁用仍然登录的用户,(似乎)该用户保持登录状态直到 http-session 结束,但我希望用户在我将他设置为禁用后立即注销。我该怎么做?

【问题讨论】:

标签: java spring spring-mvc spring-security


【解决方案1】:

假设您有一个正在运行的能够禁用用户的 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。

【讨论】:

  • 如何使用 java config 进行配置?我有 configure(HttpSecurity http) { http.securityContext().securityContextRepository(new RefreshingUserDetailsS​​ecurityContextRepository()) 但是这个类需要构造函数参数?
猜你喜欢
  • 2018-04-10
  • 2012-11-10
  • 2014-04-16
  • 2020-04-02
  • 2014-06-04
  • 2017-11-05
  • 2016-01-08
  • 2021-12-19
  • 1970-01-01
相关资源
最近更新 更多