Java SpringMVC,从服务层的安全上下文中获取主体 在spring controller中获取主体作为参数,然后通过SecurityContextHolder.getContext().getAuthentication().getPrincipal()将

Java SpringMVC,从服务层的安全上下文中获取主体 在spring controller中获取主体作为参数,然后通过SecurityContextHolder.getContext().getAuthentication().getPrincipal()将,java,spring,spring-mvc,spring-security,Java,Spring,Spring Mvc,Spring Security,SpringMVC,从服务层的安全上下文中获取主体 在spring controller中获取主体作为参数,然后通过SecurityContextHolder.getContext().getAuthentication().getPrincipal()将其传递给服务层,而不是通过SecurityContextHolder.getContext() 不检查getAuthentication()和getPrincipal()对象是否处处为null(类似于自定义包装器),在服务层中获取主体详细信息的

SpringMVC,从服务层的安全上下文中获取主体
  • 在spring controller中获取主体作为参数,然后通过SecurityContextHolder.getContext().getAuthentication().getPrincipal()将其传递给服务层,而不是通过SecurityContextHolder.getContext()
  • 不检查
    getAuthentication()
    getPrincipal()
    对象是否处处为null(类似于自定义包装器),在服务层中获取主体详细信息的最佳方法是什么
    • 您的服务API将更易于使用。您将直接看到对主体的依赖,所以您不会在主体不存在的环境中错误地调用某些服务方法
    • 一般来说,对SpringSecurity代码的依赖性越小,迁移到新的SpringSecurity版本的问题就越少
    • 您将能够在不存在Spring安全性的环境中重用您的服务层
  • 准备一些包装类(例如AuthenticationService)。向其中添加getPrincipal()方法。执行你的检查。到处注入AuthenticationService,而不是直接调用SecurityContextHolder

  • 如果我需要为特定用户获取一些数据,我认为在服务层中获取主体(例如用户名)更安全,因为在这个(限制)和数据库之间的层更少。因此,它是唯一剩下的dao,而不是在控制器中获取主体(之间的附加服务层)。但另一方面,正如您所说,服务层可以更加可重用。你们怎么看?一个主要的对象是由web层持有和保存的。所以对我来说,从控制层到服务层都有一个主体,这看起来很自然。另一点是静态依赖关系对单元测试不利:。我没有看到任何安全问题,因为pincipal实例是不可变的(通常,此时将从实际实现中删除密码)。抱歉耽搁了。我在AFK工作了很长时间。在扩展BaseService(服务层)中使用选项2安全吗?在“安全”下是什么意思?它是线程安全的,因为主体是不可变的。但是,您可以有一个与多线程相关的litlle throuble。假设线程A检查身份验证是否为空,如下所示:
    SecurityContextHolder.getContext().getAuthentication()!=空
    。然后线程B执行
    SecurityContextHolder.clearContext()
    。在此线程之后,可能会在此处有NPE:
    SecurityContextHolder.getContext().getAuthentication().getPrincipal()
    。要避免这种情况,请始终获取一个参考
    Authentication Authentication=SecurityContextHolder.getContext().getAuthentication()
    。您可能会发现这些问题的答案很有用。也可能有用。使用静态方法创建抽象类是一个好的解决方案吗?我可以将
    SecurityContextHolder.getContext().getAuthentication().getPrincipal()
    ?之后,我可以在服务层使用它。再次阅读我给你的第二个链接。没有什么可以阻止您在服务中使用这种方法,如果您使用一个接口,您也可以将其交换以进行测试。感谢您提供的解决方案。但通过使用接口和实现,我需要将其注入到几乎每个服务中,或者可以注入到基本服务类中。如何使用静态方法(从我上面的评论)?什么更好?