psql:连接到数据库后如何切换到不同的角色?

发布于 2024-09-05 04:03:42 字数 869 浏览 2 评论 0原文

是否可以更改用户在初始连接后与 postgres 交互时使用的 postgresql 角色?

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

我缺少什么?

更新:我已经按照@Milen的建议尝试了SET ROLESET SESSION AUTHORIZATION,但是如果用户不这样做,这两个命令似乎都不起作用超级用户:

$ 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

Is it possible to change the postgresql role a user is using when interacting with postgres after the initial connection?

The database(s) will be used in a web application and I'd like to employ database level rules on tables and schemas with connection pooling. From reading the postgresql documentation it appears I can switch roles if I originally connect as a user with the superuser role, but I would prefer to initially connect as a user with minimal permissions and switch as necessary. Having to specify the user's password when switching would be fine (in fact I'd prefer it).

What am I missing?

Update: I've tried both SET ROLE and SET SESSION AUTHORIZATION as suggested by @Milen however neither command seems to work if the user is not a superuser:

$ 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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

我们只是彼此的过ke 2024-09-12 04:04:05

如果有人仍然需要它(就像我一样)。

指定的 role_name 必须是当前会话用户所属的角色。
https://www.postgresql.org/docs/10/sql-set -role.html

我们需要使当前会话用户成为角色的成员:

create role myrole;
set role myrole;
grant myrole to myuser;
set role myrole;

产生:

Role ROLE created.


Error starting at line : 4 in command -
set role myrole
Error report -
ERROR: permission denied to set role "myrole"

Grant succeeded.


Role SET succeeded.

If someone still needs it (like I do).

The specified role_name must be a role that the current session user is a member of.
https://www.postgresql.org/docs/10/sql-set-role.html

We need to make the current session user a member of the role:

create role myrole;
set role myrole;
grant myrole to myuser;
set role myrole;

produces:

Role ROLE created.


Error starting at line : 4 in command -
set role myrole
Error report -
ERROR: permission denied to set role "myrole"

Grant succeeded.


Role SET succeeded.
独自←快乐 2024-09-12 04:03:54
--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 权限。

您希望在数据库会话开始时设置角色并在会话结束时重置它。在 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);
    }
}
--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 is now in the neil group, so webgui can call set role neil . However, webgui did not inherit neil's permissions.

Later, login as webgui:

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

set role neil;

webgui does not need superuser permission for this.

You want to set role at the beginning of a database session and reset it at the end of the session. In a web app, this corresponds to getting a connection from your database connection pool and releasing it, respectively. Here's an example using Tomcat's connection pool and 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);
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文