在 Cherrypy 中启用摘要身份验证 server.conf

Enabling digest authentication in Cherrypy server.conf

要在 Cherrypy 中启用摘要验证,他们说使用这样的代码:

from cherrypy.lib import auth_digest

USERS = {'jon': 'secret'}

conf = {
   '/protected/area': {
        'tools.auth_digest.on': True,
        'tools.auth_digest.realm': 'localhost',
        'tools.auth_digest.get_ha1': auth_digest.get_ha1_dict_plain(USERS),
        'tools.auth_digest.key': 'a565c27146791cfb'
   }
}

cherrypy.quickstart(myapp, '/', conf)

而且效果很好。但是我使用 server.conf 文件来存储我的应用程序的所有配置,我想继续使用这个文件。所以我在那里写了新的部分:

[/protected/area]
tools.auth_digest.on = True
tools.auth_digest.realm = 'localhost',
tools.auth_digest.get_ha1 = auth_digest.get_ha1_dict_plain({'jon': 'secret'}),
tools.auth_digest.key = 'a565c27146791cfb'

之后我遇到了错误:

ValueError: ('Config error in section: \'/protected/area\', option: \'tools.auth_digest.get_ha1\', value: "auth_digest.get_ha1_dict_plain({\'jon\': \'secret\'}),". Config values must be valid Python.', 'TypeError', ("unrepr could not resolve the name 'auth_digest'",))

我明白原因,但我不知道如何为 "valid Python" 提供 server.conf。请帮助我。

您可以在您的应用程序中调用该函数并在配置中使用生成的函数,例如:

myapp/__init__.py:

get_ha1 = auth_digest.get_ha1_dict_plain({'jon': 'secret'})

server.conf:

[/protected/area]
tools.auth_digest.on = True
tools.auth_digest.realm = 'localhost'
tools.auth_digest.get_ha1 = myapp.get_ha1
tools.auth_digest.key = 'a565c27146791cfb'

问题是您在代码中定义凭据。

可能值得一提的是,您可以使用其他功能,而不仅仅是您在字典中使用纯文本密码定义用户的功能,您可以使用来自 cherrypy.lib.auth_digest.get_ha1_file_htdigest 的 htdigest 文件或实现您的自己的 ha1 函数就像 get_ha1_dict_plain returns:

def get_ha1_dict_plain(user_password_dict):
    """Returns a get_ha1 function which obtains a plaintext password from a
    dictionary of the form: {username : password}.
    If you want a simple dictionary-based authentication scheme, with plaintext
    passwords, use get_ha1_dict_plain(my_userpass_dict) as the value for the
    get_ha1 argument to digest_auth().
    """
    def get_ha1(realm, username):
        password = user_password_dict.get(username)
        if password:
            return md5_hex('%s:%s:%s' % (username, realm, password))
        return None

    return get_ha1

我实现了一个从数据库中获取 ha1 的方法,例如使用这个 sqlalchemy 模型 (https://github.com/cyraxjoe/maki/blob/master/maki/db/models.py#L174-L189):

class User(Base):
    __tablename__ = 'users'

    name   = Column(String(32), unique=True, nullable=False)
    vname  = Column(String(64))
    email  = Column(String(64), nullable=False)
    ha1    = Column(String(32), nullable=False)
    active = Column(Boolean, server_default='True')


    @validates('ha1')
    def validates_ha1(self, key, passwd):
        if self.name is None:
            raise Exception('Set the name first')
        pack = ':'.join([self.name, maki.constants.REALM, passwd])
        return hashlib.md5(pack.encode()).hexdigest()

还有一个get_ha1函数(https://github.com/cyraxjoe/maki/blob/master/maki/db/utils.py#L63):

def get_user_ha1(realm, username):
    # realm is not used the stored hash already used it.
    user = db.ses.query(db.models.User).filter_by(name=username).scalar()
    if user is not None:
        return user.ha1

重要的是 ha1 只是 "user:real:password" 的 md5 散列,您可以在很多不同的地方实现它。