2010-06-08 21 views
36

是否有可能在初始连接之后更改用户在与postgres交互时使用的postgresql角色?连接到数据库后切换角色

数据库将用于Web应用程序,我想在连接池中使用表和模式的数据库级规则。从阅读postgresql文档看来,如果我最初以具有超级用户角色的用户身份进行连接,则可以切换角色,但我更愿意以最低权限进行连接,并根据需要进行切换。切换时必须指定用户的密码才算正常(事实上,我更喜欢它)。

我错过了什么?

更新:我都试过SET ROLESET SESSION AUTHORIZATION通过@Milen的建议既不不过似乎命令,如果用户不是超级用户的工作:

$ psql -U test 
psql (8.4.4) 
Type "help" for help. 

test=> \du test 
      List of roles 
Role name | Attributes | Member of  
-----------+------------+---------------- 
test  |   | {connect_only} 

test=> \du test2 
      List of roles 
Role name | Attributes | Member of  
-----------+------------+---------------- 
test2  |   | {connect_only} 

test=> set role test2; 
ERROR: permission denied to set role "test2" 
test=> \q 

回答

7
+0

我试过两个命令都无济于事,如果连接用户不是超级用户,我得到权限被拒绝的错误。我已经用更多信息更新了这个问题 – 2010-06-09 01:58:00

+1

我相信你的用户必须是你已经想要设置的角色的成员,并且在他们的用户上拥有NOINHERITS属性,以便他们不是默认的。那么你应该升级和降级。但他们必须成为这个角色的成员。 – rfusca 2010-06-09 03:26:12

30
--create a user that you want to use the database as: 

create role neil; 

--create the user for the web server to connect as: 

create role webgui noinherit login password 's3cr3t'; 

--let webgui set role to neil: 

grant neil to webgui; --this looks backwards but is correct. 

webgui现在是neil组中,所以webgui可以调用set role neil。但是,webgui未继承neil的权限。

后来,作为登录的WebGUI:

psql -d some_database -U webgui 
(enter s3cr3t as password) 

set role neil; 

webgui并不需要为这个superuser许可。

您想在数据库会话开始时使用set role,并在会话结束时将其重置。在Web应用程序中,这对应于从数据库连接池获取连接并分别释放它。以下是使用Tomcat的连接池和Spring Security的示例:

public class SetRoleJdbcInterceptor extends JdbcInterceptor { 

    @Override 
    public void reset(ConnectionPool connectionPool, PooledConnection pooledConnection) { 

     Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); 

     if(authentication != null) { 
      try { 

       /* 
        use OWASP's ESAPI to encode the username to avoid SQL Injection. Can't use parameters with SET ROLE. Need to write PG codec. 

        Or use a whitelist-map approach 
       */ 
       String username = ESAPI.encoder().encodeForSQL(MY_CODEC, authentication.getName()); 

       Statement statement = pooledConnection.getConnection().createStatement(); 
       statement.execute("set role \"" + username + "\""); 
       statement.close(); 
      } catch(SQLException exp){ 
       throw new RuntimeException(exp); 
      } 
     } 
    } 

    @Override 
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 

     if("close".equals(method.getName())){ 
      Statement statement = ((Connection)proxy).createStatement(); 
      statement.execute("reset role"); 
      statement.close(); 
     } 

     return super.invoke(proxy, method, args); 
    } 
}