在初始连接后与postgres交互时,是否可以更改用户正在使用的postgresql角色?
数据库将在Web应用程序中使用,我想对具有连接池的表和模式使用数据库级规则。从阅读postgresql文档看来,如果我最初作为具有超级用户角色的用户连接,我可以切换角色,但我更愿意最初以具有最小权限的用户连接并根据需要进行切换。切换时必须指定用户的密码才行(实际上我更喜欢它)。
我错过了什么?
更新:我按照@Milen的建议尝试了SET ROLE
和SET 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
答案 0 :(得分:38)
--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);
}
}
答案 1 :(得分:11)
答案 2 :(得分:0)
如果有人仍然需要它(像我一样)。
指定的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.