【问题标题】:CherryPy REST AuthenticationCherryPy REST 身份验证
【发布时间】:2015-04-15 08:22:04
【问题描述】:

我对 Python 和 CherryPy 还很陌生,我正在尝试构建一个基本的 Web 应用程序,该应用程序将使用 RESTful API 从服务器查询数据。我试图从一开始就以正确的方式做到这一点。我无法弄清楚的一部分是 API 的身份验证,因为 REST 应该是无状态的,并且您不使用会话。

我希望能够将我的 API 与没有 Cookie 的“本地客户端”一起使用,因此不能选择使用会话 Cookie。将使用 HTML 中的 AJAX 访问数据。 OAuth 似乎是一种选择,但我不想依赖第三方提供登录服务(Facebook 几周前几乎离线了一天)

谁能指出我正确的方向,这将与 CherryPy 一起使用?

【问题讨论】:

  • OAuth 似乎是一种选择?完成授权后,您仍然必须以某种方式保持会话,例如在 cookie 中或通过更改连接状态。基本上你所说的是“我希望服务器知道我在不知道这一点的情况下获得了授权”。我建议改变你的假设,让那些“本地客户端”支持 cookie(或等效的)。否则我怀疑你能做的很多。
  • @freakish Cookie 不应该与 REST 一起使用,它们会变成有状态的。 REST 应该通过令牌进行身份验证,而不必在服务器上存储任何状态或会话数据。看看http://restcookbook.com/Basics/loggingin/
  • 老兄,cookie 和令牌在概念上没有区别。这只是一个词。除了你会在客户端存储那个令牌的地方吗?如果你说客户端不支持cookies。并且连接不会通过 cookie 变为有状态。
  • 客户端/用户代理是无状态的,API/服务器是无状态的是有区别的。 REST 要求仅适用于服务器。基本前提是要么服务器记住谁登录(在请求之间),这在服务器上是有状态的,要么客户端必须发送一些东西(cookie/HTTP-auth/token/signature)来在每个请求上验证自己,在这种情况下,服务器需要检查每个请求。

标签: rest authentication cherrypy


【解决方案1】:

RESTful 身份验证没有“正确的方法”。 REST 本身并不是 API 银弹。有您对它的要求,以及您需要权衡的解决方案及其优缺点。不过,我将介绍可在 CherryPy 上开箱即用的 HTTP 标准方法。

您在评论中链接的文章非常清楚地说明了以无状态方式进行身份验证的简单方法——HTTPS 上的Basic Auth。还有Digest Auth,它不会像这样传输密码并防止重放攻击,所以可以在纯HTTP上使用它。

#!/usr/bin/env python
# -*- coding: utf-8 -*-


import cherrypy


userpassdict  = {'user1': 'passwd'}
checkpassword = cherrypy.lib.auth_basic.checkpassword_dict(userpassdict)
get_ha1       = cherrypy.lib.auth_digest.get_ha1_dict_plain(userpassdict)

config = {
  'global' : {
    'server.socket_host' : '127.0.0.1',
    'server.socket_port' : 8080,
    'server.thread_pool' : 8
  },
  '/' : {
    # HTTP verb dispatcher
    'request.dispatch': cherrypy.dispatch.MethodDispatcher(),
    # JSON response
    'tools.json_out.on' : True,
    # Basic Auth
    'tools.auth_basic.on'            : True,
    'tools.auth_basic.realm'         : 'Walled garden',
    'tools.auth_basic.checkpassword' : checkpassword,
    # Digest Auth
    #'tools.auth_digest.on'      : True,
    #'tools.auth_digest.realm'   : 'Walled garden',
    #'tools.auth_digest.get_ha1' : get_ha1,
    #'tools.auth_digest.key'     : 'put random secret here',
  }
}


class Document:
  '''Test like:
  curl --user user1:passwd --request GET http://localhost:8080/api/document
  curl --user user1:passwd --request GET http://localhost:8080/api/document/2
  curl --user user1:passwd --request POST --data name="new entry" http://localhost:8080/api/document
  curl --user user1:passwd --request PUT --data name="new entry2" http://localhost:8080/api/document/4
  curl --user user1:passwd --request DELETE http://localhost:8080/api/document/4
  '''

  _store  = None
  exposed = True


  def __init__(self):
    self._store = {
      1 : {'id': 1, 'name': 'foo'},
      2 : {'id': 2, 'name': 'bar'},
      3 : {'id': 3, 'name': 'baz'},
      4 : {'id': 4, 'name': 'qux'},
    }

  def GET(self, id = None):
    if id:
      return self._store[int(id)]
    else:
      return self._store.values()

  def POST(self, **kwargs):
    id = max(self._store.keys()) + 1
    self._store[id] = {'id': id, 'name': kwargs['name']}
    return id    

  def PUT(self, id, **kwargs):
    self._store[int(id)].update(kwargs)

  def DELETE(self, id):
    self._store.pop(int(id))


if __name__ == '__main__':
  cherrypy.quickstart(Document(), '/api/document', config)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-12
    • 1970-01-01
    • 2011-07-15
    • 2015-04-14
    • 2011-11-01
    • 1970-01-01
    相关资源
    最近更新 更多