Spring security Spring安全性:按名称注销、锁定或禁用用户

Spring security Spring安全性:按名称注销、锁定或禁用用户,spring-security,Spring Security,我有一个使用spring security的测试应用程序,它有3个用户[suzy、frank、julie]。我的应用程序将事件发送到外部安全分析系统。该系统分析事件以确定它是否是“攻击”,然后应用程序轮询该系统以查看是否有任何事件被认为需要响应。下面是一个例子: bob执行操作1(已发送事件) bob执行(错误)2(已发送事件) bob执行操作3(已发送事件) 应用程序轮询外部系统并发现bob现在应该注销 鲍勃注销(怎么注销?) bob的下一个请求被重定向到登录页面 请注意: 外部分析系统正在

我有一个使用spring security的测试应用程序,它有3个用户[suzy、frank、julie]。我的应用程序将事件发送到外部安全分析系统。该系统分析事件以确定它是否是“攻击”,然后应用程序轮询该系统以查看是否有任何事件被认为需要响应。下面是一个例子:

  • bob执行操作1(已发送事件)
  • bob执行(错误)2(已发送事件)
  • bob执行操作3(已发送事件)
  • 应用程序轮询外部系统并发现bob现在应该注销
  • 鲍勃注销(怎么注销?)
  • bob的下一个请求被重定向到登录页面
  • 请注意:

    • 外部分析系统正在检查spring security不会检查的东西(想想欺诈分析之类的东西)
    • “轮询”检查本质上是一个后台线程,因此它不会阻止请求
    我基本上希望我正在采取的任何行动都能对bob的下一个请求产生影响。我想要一些像:

    loadUserByUsername("bob").disable();
    
    我现在希望构建的功能只是:

    • 注销
    • 禁用
    我可以通过缓存用户会话然后使其无效来注销,不过我更喜欢一种更好的方式(即
    loadByUsername(“bob”).logout()
    )。但我不知道如何执行帐户禁用


    如果可能的话,我希望不必构建核心API的定制实现。我希望这是任何使用spring security的人都可以轻松集成此功能的地方。

    我将把它分解为两个问题:

    以编程方式注销用户 不幸的是,如果不以某种方式扩展核心API,我认为没有办法做到这一点。幸运的是,与核心API的集成相当简单

    我概述了几种方法,因为我不确定“背景方法”是否提供了很多优势(稍后将对此进行详细介绍)

    自定义SecurityContextRepository 在这个时候,我认为这是最好的办法

    后台线程方法(根据请求)是有意义的,这样在向应用程序发出请求时就不必阻塞。但是,如果没有一些共享数据存储,您就无法轻松地与另一个线程通信(更不用说集群环境实例中另一台计算机上的另一个进程了)

    Spring Security获取当前用户的方式是使用
    SecurityContextRepository
    实现。默认实现从
    HttpSession
    获取用户。您可以这样做:

    GET /j_spring_security_logout HTTP/1.1
    Host: www.example.org
    Cookie: JSESSIONID=<some-id>;
    
    公共类SecurityAnalyzerSecurityContextRepository
    实现SecurityContextRepository{
    专用最终安全分析器SecurityAnalyzer;
    私人最终证券内容临时代表;
    public SecurityAnalyzer SecurityContextExtrepository(SecurityAnalyzer SecurityAnalyzer){
    这(securityAnalyzer,新的HttpSessionSecurityContextRepository());
    }
    public SecurityAnalyzer SecurityContextRepository(SecurityAnalyzer SecurityAnalyzer,SecurityContextRepository委托){
    this.securityAnalyzer=securityAnalyzer;
    this.delegate=委托;
    }
    公共安全上下文加载上下文(HttpRequestResponseHolder请求响应Holder){
    SecurityContext上下文=delegate.loadContext(requestResponseHolder);
    Authentication=context.getAuthentication();
    if(身份验证==null){
    返回上下文;
    }
    String principal=authentication.getName();
    //您的SecurityAnalyzer实现需要实现isEvil
    if(securityAnalyzer.isEvil(委托人)){
    返回SecurityContextHolder.createEmptyContext();
    }
    返回上下文;
    }
    public void saveContext(SecurityContext上下文、HttpServletRequest请求、,
    HttpServletResponse(响应){
    saveContext(上下文、请求、响应);
    }
    公共布尔containsContext(HttpServletRequest){
    返回delegate.containsContext(请求);
    }
    }
    
    其思想是,您可以委托给现有的
    SecurityContextRepository
    ,并验证用户是否被确定为邪恶

    或者,您可以提供一个
    SecurityContextRepository
    实现,该实现从后台线程可以写入的存储加载。无论哪种方式,尽管有一个对商店的阻塞呼叫

    背景线程方法 注意:我认为这不是正确的方法,因此这个答案没有那么详细

    第一步是编写轮询外部系统的后台任务。显然,Spring Security无法提供此步骤,因为它不知道如何与外部系统交互

    此操作的代码可能类似于:

    SecurityAnalyzer=。。。
    Set evillusernames=analyzer.getandremovenewevillusernames();
    ... 如何处理用户名。。。
    
    现在的问题是如何处理这些用户名。默认情况下,Spring Security将从
    HttpSession
    获取当前用户。大多数Servlet容器默认将
    HttpSession
    实现持久化为内存中的
    Map
    。Spring Security无法获取对此
    映射的引用

    直接使用JSESSIONID 一种选择是,如果我们能够获得每个用户的JSESSIONID,我们可以发出如下请求:

    GET /j_spring_security_logout HTTP/1.1
    Host: www.example.org
    Cookie: JSESSIONID=<some-id>;
    
    然后使用响应,您可以使用令牌发布帖子:

    POST /logout HTTP/1.1
    Host: www.example.org
    Cookie: JSESSIONID=<some-id>;
    
    _csrf=<csrf-token>
    
    POST/logout HTTP/1.1
    主持人:www.example.org
    Cookie:JSESSIONID=;
    _csrf=
    
    此时您可能会问,但我如何知道JSESSIONID?一种选择是使用Spring Security的。但是,开箱即用的实现不适用于集群实现