每个Spring Security会话使用具有专用数据源连接的Hibernate会话

时间:2016-10-05 21:47:28

标签: java spring hibernate session

是否可以在运行时更改theme(或创建新的)数据库身份验证,并将其链接到当前登录的Web用户?

E.g。当特定Hibernate Session - 受管用户登录时,使用其他数据库角色重新连接,并在该会话的http会话的整个生命周期内使用该连接?

2 个答案:

答案 0 :(得分:0)

hibernate会话和http会话没有关系,我有点难以理解你的问题。如果您要在http会话中存储用户详细信息(例如角色),则在描述角色已更改但用户仍具有旧权限时会出现此问题,因为Spring Security正在从会话中读取用户详细信息数据库。但是,如果您只存储用户ID而不在http会话中保留有关用户的任何信息,则不会出现刷新问题。通常,您甚至不会将用户存储在会话中,因为您只能访问Spring中的主体。 Hibernate会话是根据事务创建和关闭的。您应该使用事务,以便数据库为您处理所有并发问题,并且您不必担心是否例如用户密码在其他事务将要使用时被更改。

通常,您不应该在Http会话中存储数据库中的任何内容。这是你追求的吗?

编辑还有点不清楚你在问什么,我会猜测。您是否希望为数据库创建新的数据库凭据,具有类似于mysql workbench中的特权,然后在用户登录时使用与这些凭据的数据库连接进行每个Http会话?

Spring中没有机制来执行此操作,因为这将依赖于数据库。不建议每个Http会话创建一个数据库连接,因为你将失去你Hibernate和Spring提供的漂亮的小连接池优化。如果您的应用程序拥有大量用户,那么这么多连接会受到很大的性能影响,如果您有很多用户,甚至可能会冻结。我需要澄清的是,您可能与数据库建立了开放式连接,但是您不能长时间打开休眠会话,它们只是在需要时与数据库连接进行通信的包装器。虽然我不建议你这样做,如果你在我的团队中,橄榄球会阻止你阻止你,我想有两种方法:

首先,您必须通过Java运行某些脚本来在命令行上创建凭据。然后,您需要创建一个会话数据源,并将其连接到您的所有Daos。您无法使用任何Spring的东西,如@Transactional或@PreAuthorize等。 (虽然你仍然可以使用@PreAuthorize,但不要使用hasRole,或任何会与错误的数据源对话的函数)。您只需手动执行权限逻辑,并手动编写hibernate会话。

如果这对你来说不够好,那么你可以去疯狂的疯子,并购买一台功能非常强大的服务器并启动另一个克隆'每个http会话的Spring Webapp完全相同,除了它有不同的根URL和新的连接配置。然后将该用户重定向到他们的个人webapp,谈论一流的服务。

老实说,无论哪种方式,这都是一个非常糟糕的主意,并且您可以通过使用Spring Security实现相同的用户体验。数据库连接只是最佳使用的资源。我不会给每个webapp用户提供他们自己的连接,只不过我会给公司的每个员工自己的私人厕所。相反,我给他们一张钥匙卡,允许共享可用的厕所,你应该这样做。

答案 1 :(得分:0)

我不确定每个用户拥有一个专用的数据库会话是否可行。即使技术上可行,具有大量用户群的应用程序也不会很好地扩展。另一种方法是配置标准连接池,并在每次从池中签出时将连接与特定Web应用程序用户关联。

这里有一些讨论(从Oracle的角度来看,但无论RDBMS如何,相同的原则都适用):

  

许多应用程序使用会话池来设置多个会话   被多个应用程序用户重用。用户进行身份验证   它们本身是一个使用单一身份的中间层应用程序   登录数据库并维护所有用户连接。在   这个模型,应用程序用户是经过身份验证的用户   应用程序的中间层,但数据库不知道的人.....中   在这些情况下,应用程序通常作为单个连接   数据库用户和所有操作都被视为该用户。因为所有用户   会话创建为同一个用户,此安全模型可以实现   很难为每个用户实现数据分离。的这些   应用程序可以使用CLIENT_IDENTIFIER属性来保留   真正的应用程序用户身份到数据库。

https://docs.oracle.com/cd/B19306_01/network.102/b14266/apdvprxy.htm#i1010372

如何实现这一点将在下面的Spring文档的8.2节中讨论。请注意,虽然这是隐藏在特定于Spring的Oracle扩展的部分中,但8.2节(与8.1不同)中没有任何内容是特定于Oracle的(除了执行的语句之外),并且一般方法应该适用于任何数据库只需指定相关的过程调用或SQL:

http://docs.spring.io/spring-data/jdbc/docs/current/reference/html/orcl.connection.html

我对Postgres不太熟悉,但我想你想在每次Connection checkout上做的调用都是这样的:

https://www.postgresql.org/docs/8.4/static/sql-set-role.html

Spring文档中给出的示例使用XML配置。如果您使用的是Java配置,那么它看起来像:

@Component
@Aspect
public class ClientIdentifierConnectionPreparer implements ConnectionPreparer
{
  @AfterReturning(pointcut = "execution(* *.getConnection(..))", returning = "connection")
  public Connection prepare(Connection connection) throws SQLException
  {
    SecurityContextHolder.getContext().getAuthentication().getPrincipal();
    String webAppUser = //;

    CallableStatement cs = connection.prepareCall("my postgres statement");
    cs.setString(1, webAppUser);
    cs.execute();
    cs.close();

    return connection;
  }
}

@Configuration
@EnableAspectJAutoProxy
public class SomeConfigurationClass
{

}