如何使用python在linux中以不同用户的身份运行部分代码

如何使用python在linux中以不同用户的身份运行部分代码,python,Python,我正在寻找一种方法来运行python代码/函数的一部分,以便在Linux中作为不同的用户运行,而不是生成另一个脚本 例如: def function1(args): # stuffs def function2(): # stuffs 我想通过传递两个参数从function2调用函数function1,而function1应该接受这些参数,并作为不同的用户执行文件并返回结果。因为我必须在整个执行过程中调用一些东西,所以我不想为一小段代码创建多个脚本。基本上,我尝试在函数fu

我正在寻找一种方法来运行python代码/函数的一部分,以便在Linux中作为不同的用户运行,而不是生成另一个脚本

例如:

def function1(args):
    # stuffs 

def function2():
    # stuffs

我想通过传递两个参数从
function2
调用函数
function1
,而
function1
应该接受这些参数,并作为不同的用户执行文件并返回结果。因为我必须在整个执行过程中调用一些东西,所以我不想为一小段代码创建多个脚本。基本上,我尝试在函数
function1
中连接数据库(数据库连接只能作为特定用户进行),然后运行查询并获得结果

这比你想象的要难一点。首先,Python提供并更改正在运行的脚本的当前用户/组,您可以创建一个上下文管理器来为您进行投标,并自动恢复到当前正在执行的用户:

import os

class UnixUser(object):

    def __init__(self, uid, gid=None):
        self.uid = uid
        self.gid = gid

    def __enter__(self):
        self.cache = os.getuid(), os.getgid()  # cache the current UID and GID
        if self.gid is not None:  # GID change requested as well
            os.setgid(self.gid)
        os.setuid(self.uid)  # set the UID for the code within the `with` block

    def __exit__(self, exc_type, exc_val, exc_tb):
        # optionally, deal with the exception
        os.setuid(self.cache[0])  # revert back to the original UID
        os.setgid(self.cache[1])  # revert back to the original GID
为了测试它:

def test():
    print("Current UID: {}".format(os.getuid()))  # prints the UID of the executing user

test()  # executes as the current user

with UnixUser(105):
    test()  # executes as the user with UID: 105
您甚至可以创建一个整洁的装饰器来选择某些函数应该始终作为另一个用户执行:

def as_unix_user(uid, gid=None):  # optional group
    def wrapper(func):
        def wrapped(*args, **kwargs):
            with UnixUser(uid, gid):
                return func(*args, **kwargs)  # execute the function
        return wrapped
    return wrapper

def test1():
    print("Current UID: {}".format(os.getuid()))  # prints the UID of the executing user

@as_unix_user(105)
def test2():
    print("Current UID: {}".format(os.getuid()))  # prints the UID of the executing user

test1()  # executes as the current user
test2()  # executes as the user with UID: 105
踢球者?除了不具有线程安全性之外,只有当前用户和您希望执行函数的用户都具有并且(可选)具有功能时,它才会起作用

您可以只让一个具有这些功能的用户运行主脚本,然后在必要时进行fork,只在fork进程上更改UID/GID:

import os

def as_unix_user(uid, gid=None):  # optional group
    def wrapper(func):
        def wrapped(*args, **kwargs):
            pid = os.fork()
            if pid == 0:  # we're in the forked process
                if gid is not None:  # GID change requested as well
                    os.setgid(gid)
                os.setuid(uid)  # set the UID for the code within the `with` block
                func(*args, **kwargs)  # execute the function
                os._exit(0)  # exit the child process
        return wrapped
    return wrapper

def test1():
    print("Current UID: {}".format(os.getuid()))  # prints the UID of the executing user

@as_unix_user(105)
def test2():
    print("Current UID: {}".format(os.getuid()))  # prints the UID of the executing user

test1()  # executes as the current user
test2()  # executes as the user with UID: 105
这里的踢球者?您无法从forked函数获取返回数据。如果您需要它,您必须通过管道将其返回到父进程,然后在父进程中等待它完成。您还需要选择一种在进程之间传递数据的格式(如果足够简单,我建议使用JSON或使用本机
pickle


在这一点上,您已经完成了模块所做工作的一半,因此您不妨将您的函数作为子流程启动并完成它。如果你必须经历这样的困难才能达到你想要的结果,那么很可能是你原来的设计出了问题。在您的情况下,为什么不为当前用户提供访问数据库的权限呢?用户需要具备切换到另一个用户的能力,这样您就不会从中获得任何安全性方面的好处—这只会使您的生活变得复杂。

您不能这样做。你必须使用两个进程。你是说一个不同的数据库用户还是一个不同的linux用户?@Mohl不同的linux用户对我来说很好。我认为这是不可能的,除非你进入另一台计算机@ᴡʜᴀᴄᴋᴀᴍᴀᴅᴏᴏᴅʟᴇ仅当我们尝试在远程服务器上执行某些操作时,才需要3000 SSHing。但在我的情况下,用户只驻留在同一个系统上。感谢提供详细信息。我尝试了
os.setreuid(user\u id,user\u id)
,但是当我们仅仅更改用户id时,它不会影响该用户的环境变量。我认为最好将脚本拆分为多个脚本,并使用
su-
在子流程中运行它们。