python-eve 认证和授权

验证类型

全局验证

要实现安全认证,只需要在Eve实例化的时候传入验证类即可,这样就创建了一个全局的验证类

    from eve.auth import BasicAuth
    class MybasicAuth(BasicAuth):
        def check_auth(self, username, password, allowed_roles, resource, method):
            return username == 'admin' and password == 'admin'
                
    app = Eve(auth=MybasicAuth)

只有用户名和密码满足条件才允许访问

如果要做到对某一资源公开,其他资源安全,可以用下面的写法

    if resource in ('people','countries'):
        return True
    else:
        return username == 'admin' and password == 'secret'

同样,你可以控制method,以在某个方法上启用或者关闭验证

资源级验证

有时候要对某些资源进行特别的权限控制,这时候全局验证就不太好用了
可以重写某个资源的验证类

    people = {
        'authentication':MyEndpointAuth,
    }

其中MyEndpointAuth和上面的MybaseAuth一样继承自BasicAuth并且重写了check_auth方法,可以为每一个资源设置不同的验证方法

全局资源安全方法

在setting中加入下面的内容,可以使所有资源的GET方法都是公开的

    PUBLIC_METHODS = ['GET']
    PUBLIC_ITEM_METHODS = ['GET']

PUBLIC_METHODS 引用资源端点,例如/ people ,而PUBLIC_ITEM_METHODS引用像/people/<id>这样的单个项目。

自定义资源安全方法

可以为资源设置public_methods,public_item_methods来设置资源的访问控制,资源中的这两个属性会覆盖全局设定,利用这一特点可以设置全部资源公开但某一资源私有

    DOMAIN = {
        'invoices': {
            'public_methods': [],
            'public_item_methods': [],
             }
        }

这样invoices这个资源就被隐藏了

验证方法

使用SHA1 / HMAC进行身份验证

假设用户名和密码都存储在MongoDB中,并且密码存储为SHA1 / HMAC哈希值,我们可以用下面的方法验证用户名和密码

    from eve.auth import BasicAuth
    from werkzeug.security import check_password_hash
    from flask import current_app as app
        
    class Sha1Auth(BasicAuth):
        def check_auth(self, username, password, allowed_roles, resource, method):
            # use Eve's own db driver; no additional connections/resources are used
            accounts = app.data.driver.db['accounts']
            account = accounts.find_one({'username': username})
            return account and \
                check_password_hash(account['password'], password)

为了要测试用户名和密码,我们要事先往mongodb的accounts表中插入一条记录

    use eve
    db.createCollection("accounts")
    db.accounts.insert({username:"test1",passowrd:"pbkdf2:sha1:1000$v86Nv0hS$817921c0a065c4289416f559a2d8da3010b66727"})

密码为admin
tips:更新密码请用db.accounts.update({“username”:”test1″},{$set:{“password”:”new password”}})

之后测试登录即可

使用TOKEN验证

token验证可以看作只有用户名没有密码的验证方式,使用Token作为验证,Token本身必须具备足够的强度并且有合理的失效机制

    class TokenAuthS(TokenAuth):
        def check_auth(self, token, allowed_roles, resource, method):
            accounts = app.data.driver.db['accounts']
            return accounts.find_one({'token': token})

和SHA1/HMAC验证一样,我们要事先在数据库里存放一个token,方法类似

    db.accounts.insert({toke:"86Nv0h817921c0a065c4289416f559a2d8da3010b66727"})
    

HMAC认证

eve.auth.HMACAuth类允许自定义的类似于Amazon S3的HMAC(哈希消息认证码)认证,这基本上是一个非常安全的定制认证方案,围绕Authorization头部而构建。

要使用HMAC验证,需要通过一些外部技术(例如,向客户发送包含用户ID和秘密密钥的电子邮件)向客户端提供用户ID和密钥。 客户端将使用提供的密钥来签署所有请求。
当客户想要发送一个请求时,先建立完整的请求,然后使用密钥,在整个消息体上计算一个散列(如果需要的话还可以包含一些消息头),接下来,客户端将计算出的散列和他的用户ID添加到授权标头中的消息中,下面是一个例子:

        Authorization: johndoe:uCMfSzkjue+HSDygYB5aEg==

如果要实现类似的效果,可以这样做:
1.先往mongodb中插入一条记录,记录userid和secret_key
2.用secret_key计算出我们需要的散列值,添加到头中,eve中写法如下

    class HMACAuths(HMACAuth):
        def check_auth(self, userid, hmac_hash, headers, data, allowed_roles,
                           resource, method):
            accounts = app.data.driver.db['accounts']
            user = accounts.find_one({'userid': userid})
            if user:
                secret_key = user['secret_key']
            return user and hmac.new(bytes(secret_key.encode()), data, sha1).hexdigest() == hmac_hash

访问控制

基于角色的访问控制

在上面的内容中被故意忽略的参数allowed_roles,作用是利用角色来控制对资源的访问,要想要预览这效果,需要修改之前存在mongodb中的用户名密码,为其增加roles属性

    db.accounts.update({username:"test1"},{$set:{"roles":"admin"}})

setting中添加全局资源允许的操作角色,也可以在资源中设置覆盖全角的ALLOWED_ROLES设定

ALLOWED_ROLES = ['superadmin','admin']

之后修改check_auth方法

    def check_auth(self, username, password, allowed_roles, resource, method):
        accounts = app.data.driver.db['accounts']
        lookup = {'username': username}
        if allowed_roles:
            # 只有角色符合才允许后续操作 
            lookup['roles'] = {'$in': allowed_roles}
        account = accounts.find_one(lookup)
        return account and check_password_hash(account['password'], password)

之后用test1这个角色登录即可看到内容

用户对资源控制

这是一个仅允许资源创建者对资源进行控制的功能,需要在setting中设置AUTH_FIELD并且在资源中设置auth_field属性,我们假设添加到字段为user_id
1.首先setting.py中添加 AUTH_FIELD = []
2.然后people中添加’auth_field’:’user_id’
3.最后将check_auth方法修改为

    def check_auth(self, username, password, allowed_roles, resource, method):
        accounts = app.data.driver.db['accounts']
        account = accounts.find_one({'username': username})
        if account and '_id' in account:
            self.set_request_auth_value(account['_id'])
        return account and check_password_hash(account['password'], password)
    之后我们插入新的用户test2,用test2创建新的people资源,再用test1去查看,会发现无法获取到内容test2创建的内容

    
    原文作者:黑色芝麻
    原文地址: https://segmentfault.com/a/1190000012508882
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞