api.rst 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. .. _api_narrative:
  2. Using the :mod:`repoze.who` Application Programming Interface (API)
  3. ===================================================================
  4. .. _without_middleware:
  5. Using :mod:`repoze.who` without Middleware
  6. ------------------------------------------
  7. An application which does not use the :mod:`repoze.who` middleware needs
  8. to perform two separate tasks to use :mod:`repoze.who` machinery:
  9. - At application startup, it must create an :class:`repoze.who.api:APIFactory`
  10. instance, populating it with a request classifier, a challenge decider,
  11. and a set of plugins. It can do this process imperatively
  12. (see :ref:`imperative_configuration`), or using a declarative
  13. configuration file (see :ref:`declarative_configuration`). For the latter
  14. case, there is a convenience function,
  15. :func:`repoze.who.config.make_api_factory_with_config`:
  16. .. code-block:: python
  17. # myapp/run.py
  18. from repoze.who.config import make_api_factory_with_config
  19. who_api_factory = None
  20. def startup(global_conf):
  21. global who_api_factory
  22. who_api_factory = make_api_factory_with_config(global_conf,
  23. '/path/to/who.config')
  24. - When it needs to use the API, it must call the ``APIFactory``, passing
  25. the WSGI environment to it. The ``APIFactory`` returns an object
  26. implementing the :class:`repoze.who.interfaces:IRepozeWhoAPI` interface.
  27. .. code-block:: python
  28. # myapp/views.py
  29. from myapp.run import who_api_factory
  30. def my_view(context, request):
  31. who_api = who_api_factory(request.environ)
  32. - Calling the ``APIFactory`` multiple times within the same request is
  33. allowed, and should be very cheap (the API object is cached in the
  34. request environment).
  35. .. _middleware_api_hybrid:
  36. Mixed Use of :mod:`repoze.who` Middleware and API
  37. -------------------------------------------------
  38. An application which uses the :mod:`repoze.who` middleware may still need
  39. to interact directly with the ``IRepozeWhoAPI`` object for some purposes.
  40. In such cases, it should call :func:`repoze.who.api:get_api`, passing
  41. the WSGI environment.
  42. .. code-block:: python
  43. from repoze.who.api import get_api
  44. def my_view(context, request):
  45. who_api = get_api(request.environ)
  46. Alternately, the application might configure the ``APIFactory`` at startup,
  47. as above, and then use it to find the API object, or create it if it was
  48. not already created for the current request (e.g. perhaps by the middleware):
  49. .. code-block:: python
  50. def my_view(context, request):
  51. who_api = context.who_api_factory(request.environ)
  52. .. _writing_custom_login_view:
  53. Writing a Custom Login View
  54. ---------------------------
  55. :class:`repoze.who.api.API` provides a helper method to assist developers
  56. who want to control the details of the login view. The following
  57. BFG example illustrates how this API might be used:
  58. .. code-block:: python
  59. :linenos:
  60. def login_view(context, request):
  61. message = ''
  62. who_api = get_api(request.environ)
  63. if 'form.login' in request.POST:
  64. creds = {}
  65. creds['login'] = request.POST['login']
  66. creds['password'] = request.POST['password']
  67. authenticated, headers = who_api.login(creds)
  68. if authenticated:
  69. return HTTPFound(location='/', headers=headers)
  70. message = 'Invalid login.'
  71. else:
  72. # Forcefully forget any existing credentials.
  73. _, headers = who_api.login({})
  74. request.response_headerlist = headers
  75. if 'REMOTE_USER' in request.environ:
  76. del request.environ['REMOTE_USER']
  77. return {'message': message}
  78. This application is written as a "hybrid": the :mod:`repoze.who` middleware
  79. injects the API object into the WSGI enviornment on each request.
  80. - In line 4, this application extracts the API object from the environ
  81. using :func:`repoze.who.api:get_api`.
  82. - Lines 6 - 8 fabricate a set of credentials, based on the values the
  83. user entered in the form.
  84. - In line 9, the application asks the API to authenticate those credentials,
  85. returning an identity and a set of respones headers.
  86. - Lines 10 and 11 handle the case of successful authentication: in this
  87. case, the application redirects to the site root, setting the headers
  88. returned by the API object, which will "remember" the user across requests.
  89. - Line 13 is reached on failed login. In this case, the headers returned
  90. in line 9 will be "forget" headers, clearing any existing cookies or other
  91. tokens.
  92. - Lines 14 - 16 perform a "fake" login, in order to get the "forget" headers.
  93. - Line 18 sets the "forget" headers to clear any authenticated user for
  94. subsequent requests.
  95. - Lines 19 - 20 clear any authenticated user for the current request.
  96. - Line 22 returns any message about a failed login to the rendering template.
  97. .. _interfaces:
  98. Interfaces
  99. ----------
  100. .. automodule:: repoze.who.interfaces
  101. .. autointerface:: IAPIFactory
  102. :members:
  103. .. autointerface:: IAPI
  104. :members:
  105. .. autointerface:: IPlugin
  106. :members:
  107. .. autointerface:: IRequestClassifier
  108. :members:
  109. .. autointerface:: IChallengeDecider
  110. :members:
  111. .. autointerface:: IIdentifier
  112. :members:
  113. .. autointerface:: IAuthenticator
  114. :members:
  115. .. autointerface:: IChallenger
  116. :members:
  117. .. autointerface:: IMetadataProvider
  118. :members: