CherryPy REST身份验证

时间:2015-02-14 09:03:17

标签: rest authentication cherrypy

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

我希望能够将我的API用于"原生客户"它没有Cookie,所以使用会话Cookie不是一种选择。将使用HTML中的AJAX访问数据。 OAuth似乎是一个选项,但我不想依赖第三方提供登录服务(几周前Facebook已离线几乎一天)

任何人都可以指出我正确的方向,这可以与CherryPy一起使用吗?

1 个答案:

答案 0 :(得分:3)

RESTful身份验证没有“正确的方法”。 REST本身不是API银弹。有你的要求,以及你需要权衡利弊的解决方案。但是,我将讲述可以在开箱即用的CherryPy上运行的HTTP标准方法。

您在评论中链接的文章非常清楚以无状态方式进行身份验证的简单方法 - Basic Auth在HTTPS上。还有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)