【问题标题】:authorisation REST service in PythonPython中的授权REST服务
【发布时间】:2011-08-23 06:50:46
【问题描述】:

我正在设计以及决定是否选择 python 作为主要语言来实现软件。任务是:

  • 实现一组 RESTful Web 服务
  • 将 http 方法授权给特定的用户组,因为它需要使用 xacml 来定义策略(或者可以是另一个标准)和 saml 来获取信息。交流

【问题讨论】:

  • 您可能应该将您的代码与您的问题一起发布。我们对你的作业描述不太感兴趣。
  • @Eli Bendersky 问题是关于restful服务的访问保护,尤其是。 http 方法。从而决定,允许哪个用户在restful服务上执行目标资源的什么http方法?
  • @user748650:这里没有问题。建议可以包括任何内容。 (1) 阅读 REST,(2) 选择任何 Python Web 框架,(3) 使用该框架。 (4) 使用lxml 解析XACML。目前尚不清楚您想要什么还不是很容易获得。请提出一些具体的问题,以避免对您可能已经做过的事情提出无用的建议。
  • 你有什么问题?

标签: python web-services rest saml xacml


【解决方案1】:

如果您的问题是您可以使用哪些库来实现这些 RESTful 服务,请查看标准 python 库的 BaseHTTPServer 模块。

以下代码显示了实现一个接受 GET 请求的简单服务器是多么容易:

class MyHandler(BaseHTTPRequestHandler):

    def do_GET(self):
        try:
            f = open(curdir + sep + self.path) #self.path has /test.html
            self.send_response(200)
            self.send_header('Content-type',    'text/html')
            self.end_headers()
            self.wfile.write(f.read())
            f.close()
        except IOError:
            self.send_error(404,'File Not Found: %s' % self.path)

def main():
    try:
        server = HTTPServer(('', 80), MyHandler)
        print 'Welcome to the machine...'
        server.serve_forever()
    except KeyboardInterrupt:
        print '^C received, shutting down server'
        server.socket.close()

if __name__ == '__main__':
    main()

当然,代码不是我自己写的,我在here找到的。

【讨论】:

  • 谢谢,这部分回答了我的问题。具体来说,不是如何开发一个 RESTful 服务,而是更多关于从 REST 服务中授权主体。用例是访问保护http方法,这意味着,哪些用户可以在哪些资源上执行哪些方法?
【解决方案2】:

使用 Python,您可能希望创建一个 XACML 请求,其中包含您的用户 ID(您可以从通常在您进行身份验证之前发生的身份验证阶段获得该 ID)并添加有关用户所针对的 WS 的信息。可以是 URI,也可以是 HTTP 方法……

最后你可能会得到类似的东西:

<?xml version="1.0" encoding="UTF-8"?><xacml-ctx:Request xmlns:xacml-ctx="urn:oasis:names:tc:xacml:2.0:context:schema:os">
   <xacml-ctx:Subject SubjectCategory="urn:oasis:names:tc:xacml:1.0:subject-category:access-subject">
      <xacml-ctx:Attribute AttributeId="urn:oasis:names:tc:xacml:1.0:subject:subject-id" DataType="http://www.w3.org/2001/XMLSchema#string">
         <xacml-ctx:AttributeValue>Alice</xacml-ctx:AttributeValue>
      </xacml-ctx:Attribute>
   </xacml-ctx:Subject>
   <xacml-ctx:Resource>
      <xacml-ctx:Attribute AttributeId="urn:oasis:names:tc:xacml:1.0:resource:resource-id" DataType="http://www.w3.org/2001/XMLSchema#string">
         <xacml-ctx:AttributeValue>/someuri/myapi/target.py</xacml-ctx:AttributeValue>
      </xacml-ctx:Attribute>
   </xacml-ctx:Resource>
   <xacml-ctx:Action>
      <xacml-ctx:Attribute AttributeId="urn:oasis:names:tc:xacml:1.0:action:action-id" DataType="http://www.w3.org/2001/XMLSchema#string">
         <xacml-ctx:AttributeValue>GET</xacml-ctx:AttributeValue>
      </xacml-ctx:Attribute>
   </xacml-ctx:Action>
   <xacml-ctx:Environment>
   </xacml-ctx:Environment>
</xacml-ctx:Request>

例如,您需要使用 Python 和 lxml 构造请求。

响应看起来像

<xacml-ctx:Response xmlns:xacml-ctx="urn:oasis:names:tc:xacml:2.0:context:schema:os">
  <xacml-ctx:Result>
    <xacml-ctx:Decision>Permit</xacml-ctx:Decision>
    <xacml-ctx:Status>
      <xacml-ctx:StatusCode Value="urn:oasis:names:tc:xacml:1.0:status:ok"/>
    </xacml-ctx:Status>
  </xacml-ctx:Result>
</xacml-ctx:Response>

因此,您需要再次解析 XML 以提取决策,例如允许。我为 XACML PDP 编写了一个基本的类似 REST 的接口,您所要做的就是将 HTTP GET 发送到 URI,并将变量作为 GET 变量传递,例如http://www.xacml.eu/AuthZ/?a=alice&b=/someuri/myapi/target.py&c=GET

这有帮助吗?

【讨论】:

    【解决方案3】:

    我同意 Constantinius 的观点,BaseHTTPServer 是在 Python 中实现 RESTful 的好方法。它预装了 Python 2.7,并且在这种情况下比 gunicorn/flask/wsgi/gevent 更好地扩展。并支持您以后可能想要的流式传输。

    下面是一个示例,展示了 Web 浏览器如何对 BaseHTTPServer 进行远程 POST 调用并取回数据。

    JS(放入 static/hello.html 以通过 Python 服务):

    <html><head><meta charset="utf-8"/></head><body>
    Hello.
    
    <script>
    
    var xhr = new XMLHttpRequest();
    xhr.open("POST", "/postman", true);
    xhr.setRequestHeader('Content-Type', 'application/json');
    xhr.send(JSON.stringify({
        value: 'value'
    }));
    xhr.onload = function() {
      console.log("HELLO")
      console.log(this.responseText);
      var data = JSON.parse(this.responseText);
      console.log(data);
    }
    
    </script></body></html>
    

    Python 服务器(用于测试):

    import time, threading, socket, SocketServer, BaseHTTPServer
    import os, traceback, sys, json
    
    
    log_lock           = threading.Lock()
    log_next_thread_id = 0
    
    # Local log functiondef
    
    
    def Log(module, msg):
        with log_lock:
            thread = threading.current_thread().__name__
            msg    = "%s %s: %s" % (module, thread, msg)
            sys.stderr.write(msg + '\n')
    
    def Log_Traceback():
        t   = traceback.format_exc().strip('\n').split('\n')
        if ', in ' in t[-3]:
            t[-3] = t[-3].replace(', in','\n***\n***  In') + '(...):'
            t[-2] += '\n***'
        err = '\n***  '.join(t[-3:]).replace('"','').replace(' File ', '')
        err = err.replace(', line',':')
        Log("Traceback", '\n'.join(t[:-3]) + '\n\n\n***\n*** ' + err + '\n***\n\n')
    
        os._exit(4)
    
    def Set_Thread_Label(s):
        global log_next_thread_id
        with log_lock:
            threading.current_thread().__name__ = "%d%s" \
                % (log_next_thread_id, s)
            log_next_thread_id += 1
    
    
    class Handler(BaseHTTPServer.BaseHTTPRequestHandler):
    
        def do_GET(self):
            Set_Thread_Label(self.path + "[get]")
            try:
                Log("HTTP", "PATH='%s'" % self.path)
                with open('static' + self.path) as f:
                    data = f.read()
                Log("Static", "DATA='%s'" % data)
                self.send_response(200)
                self.send_header("Content-type", "text/html")
                self.end_headers()
                self.wfile.write(data)
            except:
                Log_Traceback()
    
        def do_POST(self):
            Set_Thread_Label(self.path + "[post]")
            try:
                length = int(self.headers.getheader('content-length'))
                req   = self.rfile.read(length)
                Log("HTTP", "PATH='%s'" % self.path)
                Log("URL", "request data = %s" % req)
                req = json.loads(req)
                response = {'req': req}
                response = json.dumps(response)
                Log("URL", "response data = %s" % response)
                self.send_response(200)
                self.send_header("Content-type", "application/json")
                self.send_header("content-length", str(len(response)))
                self.end_headers()
                self.wfile.write(response)
            except:
                Log_Traceback()
    
    
    # Create ONE socket.
    addr = ('', 8000)
    sock = socket.socket (socket.AF_INET, socket.SOCK_STREAM)
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    sock.bind(addr)
    sock.listen(5)
    
    # Launch 10 listener threads.
    class Thread(threading.Thread):
        def __init__(self, i):
            threading.Thread.__init__(self)
            self.i = i
            self.daemon = True
            self.start()
        def run(self):
            httpd = BaseHTTPServer.HTTPServer(addr, Handler, False)
    
            # Prevent the HTTP server from re-binding every handler.
            # https://stackoverflow.com/questions/46210672/
            httpd.socket = sock
            httpd.server_bind = self.server_close = lambda self: None
    
            httpd.serve_forever()
    [Thread(i) for i in range(10)]
    time.sleep(9e9)
    

    控制台日志(chrome):

    HELLO
    hello.html:14 {"req": {"value": "value"}}
    hello.html:16 
    {req: {…}}
    req
    :
    {value: "value"}
    __proto__
    :
    Object
    

    控制台日志(火狐):

    GET 
    http://XXXXX:8000/hello.html [HTTP/1.0 200 OK 0ms]
    POST 
    XHR 
    http://XXXXX:8000/postman [HTTP/1.0 200 OK 0ms]
    HELLO hello.html:13:3
    {"req": {"value": "value"}} hello.html:14:3
    Object { req: Object }
    

    控制台日志(边缘):

    HTML1300: Navigation occurred.
    hello.html
    HTML1527: DOCTYPE expected. Consider adding a valid HTML5 doctype: "<!DOCTYPE html>".
    hello.html (1,1)
    Current window: XXXXX/hello.html
    HELLO
    hello.html (13,3)
    {"req": {"value": "value"}}
    hello.html (14,3)
    [object Object]
    hello.html (16,3)
       {
          [functions]: ,
          __proto__: { },
          req: {
             [functions]: ,
             __proto__: { },
             value: "value"
          }
       }
    

    Python 日志:

    HTTP 8/postman[post]: PATH='/postman'
    URL 8/postman[post]: request data = {"value":"value"}
    URL 8/postman[post]: response data = {"req": {"value": "value"}}
    

    您还可以通过在将套接字传递给 BaseHTTPServer 之前包装套接字来轻松添加 SSL。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-07-21
      • 2016-12-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-07-19
      相关资源
      最近更新 更多