安全的Python REST API

安全的Python REST API,python,rest,authentication,flask,Python,Rest,Authentication,Flask,我正在尝试用python编写一些RESTAPI,首先我开始编写身份验证代码。我在其中一个站点上找到了用于身份验证的示例代码: from functools import wraps from flask import request, Response def check_auth(username, password): """This function is called to check if a username / password combination is va

我正在尝试用python编写一些RESTAPI,首先我开始编写身份验证代码。我在其中一个站点上找到了用于身份验证的示例代码:

from functools import wraps
from flask import request, Response

def check_auth(username, password):
    """This function is called to check if a username /
    password combination is valid.
    """
    return username == 'admin' and password == 'secret'

def authenticate():
    """Sends a 401 response that enables basic auth"""
    return Response(
    'Could not verify your access level for that URL.\n'
    'You have to login with proper credentials', 401,
    {'WWW-Authenticate': 'Basic realm="Login Required"'})

def requires_auth(f):
    @wraps(f)
    def decorated(*args, **kwargs):
        auth = request.authorization
        if not auth or not check_auth(username, password):
            return authenticate()
        return f(*args, **kwargs)
    return decorated
我已使用上述代码保护我的示例应用程序:

@app.route('/student/<studentid>', methods = ['GET'])
@requires_auth
def api_users(studentid):
    students = {'1':'ABC', '2':'XYZ', '3':'TEST'}

    if studentid in students:
        return jsonify({studentid:students[studentid]})
    else:
        return not_found()
@app.route('/student/',方法=['GET']
@需要授权
def api_用户(学生ID):
学生={'1':'ABC','2':'XYZ','3':'TEST'}
如果学生是学生:
返回jsonify({studentid:students[studentid]})
其他:
未找到返回值()
现在,我试图通过python请求/pycurl模块调用这个url。但是,无论用户名/密码是否有效,每次它都返回401错误

使用请求:

import requests, base64
usrPass = "admin:secret"
b64Val = base64.b64encode(usrPass)
from requests.auth import HTTPBasicAuth
from requests.packages.urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
res = requests.get('https://<abc.com>/student/1', auth=HTTPBasicAuth('admin','secret'), headers={'Authorization': 'Basic %s' % b64Val}, data={}, verify=False)
print res
导入请求,base64 usrPass=“管理员:机密” b64Val=base64.b64encode(usrPass) 从requests.auth导入HTTPBasicAuth 从requests.packages.urllib3.exceptions导入不安全请求警告 requests.packages.urllib3.disable_警告(不安全的RequestWarning) res=requests.get('https:///student/1,auth=HTTPBasicAuth('admin','secret'),headers={'Authorization':'Basic%s'%b64Val},data={},verify=False) 打印资源 使用curl:

myCurlPut = pycurl.Curl()
myCurlPut.setopt(pycurl.URL, "https://<abc.com>/student/1")
myCurlPut.setopt(pycurl.HTTPAUTH, pycurl.HTTPAUTH_BASIC)
myCurlPut.setopt(pycurl.USERPWD, "%s:%s" % ('admin', 'secret'))
myCurlPut.setopt(pycurl.SSL_VERIFYPEER, 0)
myCurlPut.setopt(pycurl.HTTPHEADER, ['X-HTTP-Method-Override: GET'])
myCurlPut.perform()
myCurlPut=pycurl.Curl()
myCurlPut.setopt(pycurl.URL,“https:///student/1")
myCurlPut.setopt(pycurl.HTTPAUTH,pycurl.HTTPAUTH_BASIC)
myCurlPut.setopt(pycurl.USERPWD,“%s:%s”%(“admin”,“secret”))
myCurlPut.setopt(pycurl.SSL_VERIFYPEER,0)
myCurlPut.setopt(pycurl.HTTPHEADER,['X-HTTP-Method-Override:GET']))
myCurlPut.perform()

谁能帮我解释一下为什么每次它都返回401错误。请建议

看起来您没有正确传递用户名和密码进行身份验证。应从
auth
变量中获取
username
password
的值。因此,请尝试将
requires_auth
功能更改为:

def requires_auth(f):
    @wraps(f)
    def decorated(*args, **kwargs):
        auth = request.authorization
        if not auth or not check_auth(auth.username, auth.password):
            return authenticate()
        return f(*args, **kwargs)
    return decorated

这是一个烧瓶授权的工作示例

from functools import wraps

from flask import Flask,Response,request, abort


app = Flask(__name__)

def check_auth(name,passw):
    return (name=='admin' and passw=='pass')

def requires_auth(f):
    @wraps(f)
    def decorated(*args, **kwargs):
        auth = request.authorization
        if not auth or not check_auth(auth.username, auth.password):
            abort(401)
        return f(*args, **kwargs)
    return decorated


@app.route('/')
@requires_auth
def hello():
    return "Hello World"


if __name__ == "__main__":
    app.run(debug=True)
我的请求文件:

import requests, base64
usrPass = "admin:pass"
b64Val = base64.b64encode(usrPass)
from requests.auth import HTTPBasicAuth
from requests.packages.urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
res = requests.get('http://127.0.0.1:5000/', auth=HTTPBasicAuth('admin','pass'), headers={'Authorization': 'Basic %s' % b64Val}, data={}, verify=False)
print res
如果在本地主机上运行此操作,则应使用本地主机地址。
什么是

  • 现在,用户在Auth头中将从方法2接收的令牌发送到
    用户名
    的位置
    password
    可以留空,也可以在该位置发送
    None
  • 当您收到令牌时,需要使用
    密钥
    加载令牌。可以根据您的要求处理异常。如果令牌有效,您将能够获得发送请求的用户,从而执行您的过程
  • 希望有帮助


    查看此文件以获得更详细的解释。

    您是否尝试将一些调试输出放入@requires\u auth@?当您提出请求时,
    request.authorization
    的值是多少?request.authorization的值为0谢谢您的评论。我尝试过你建议的改变,但是没有用。我认为问题在于auth=request.authorization。没有。我的服务器似乎有问题。当我试图在本地主机上执行上述代码时。。工作正常。但是,当我在服务器上执行相同的代码时,request.authorization将作为none出现。您在哪里部署了脚本?你的脚本很好,我在heroku上部署了我的一个应用程序,它使用基于令牌的身份验证,工作正常。你能帮我开发基于令牌的身份验证吗。我刚刚开始研究python。。仍然熟悉python中的身份验证。谢谢@siddhant。我可以使用密钥进行身份验证。我对此有一个疑问,假设我给出了600秒的到期时间,在这种情况下,令牌将工作10分钟。现在,为了使身份验证更加安全,我想检查令牌是否从同一个系统生成。我的意思是验证用户的机器,以避免任何安全循环漏洞(如果令牌被入侵,那么任何人都可以访问该数据,直到其过期)。我们如何验证这个场景。我对此不太了解,但您可以使用。但它是可以伪造的。
    from itsdangerous import TimedJSONWebSignatureSerializer as Serializer, BadSignature, SignatureExpired
    
    
    def gen_token(name,passw, expiration=None):
        s = Serializer(app.config['SECRET_KEY'], expires_in = expiration)
        return s.dumps(name, passw)
    
    def verify_token(token):
        serial = Serializer(app.config['SECRET_KEY'])
        try:
            data = serial.loads(token)
        except BadSignature:
            return "Error"
        except SignatureExpired:
            return "Error"
    
        name = data[0]
        passw = data[1]
    
        return name,passw