Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Normalize Authorization in both tutorials 4
- Sync content of Add login and logout views,
  Add the login.pt template, Return a logged_in
  flag, Add a logout link sections
- Normalize sections of views.py
  • Loading branch information
ppaez committed Apr 8, 2012
1 parent c226b1a commit fad5003
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 90 deletions.
120 changes: 68 additions & 52 deletions docs/tutorials/wiki/authorization.rst
Expand Up @@ -189,99 +189,115 @@ Add Login and Logout Views
We'll add a ``login`` view which renders a login form and processes
the post from the login form, checking credentials.

We'll also add a ``logout`` view to our application and provide a link
to it. This view will clear the credentials of the logged in user and
redirect back to the front page.
We'll also add a ``logout`` view to our application and
provide a link to it. This view will clear the credentials of the
logged in user and redirect back to the front page.

We'll add these views to the existing ``views.py`` file we have in our
project. Here's what the ``login`` view callable will look like:
Add the following import statements to the
head of ``tutorial/tutorial/views.py``:

.. literalinclude:: src/authorization/tutorial/views.py
:lines: 86-113
:lines: 6-13,15-17
:linenos:
:emphasize-lines: 3,6-9,11
:language: python

Here's what the ``logout`` view callable will look like:
(Only the highlighted lines need to be added.)

:meth:`~pyramid.view.forbidden_view_config` will be used
to customize the default 403 Forbidden page.
:meth:`~pyramid.security.remember` and
:meth:`~pyramid.security.forget` help to create and
expire an auth ticket cookie.

Now add the ``login`` and ``logout`` views:

.. literalinclude:: src/authorization/tutorial/views.py
:lines: 115-119
:lines: 87-120
:linenos:
:language: python

Note that the ``login`` view callable has *two* view configuration
decorators. The order of these decorators is unimportant. Each just adds a
different :term:`view configuration` for the ``login`` view callable.

The first view configuration decorator configures the ``login`` view callable
so it will be invoked when someone visits ``/login`` (when the context is a
Wiki and the view name is ``login``). The second decorator, named
``forbidden_view_config`` specifies a :term:`forbidden view`. This
configures our login view to be presented to the user when :app:`Pyramid`
detects that a view invocation can not be authorized. Because we've
configured a forbidden view, the ``login`` view callable will be invoked
whenever one of our users tries to execute a view callable that they are not
allowed to invoke as determined by the :term:`authorization policy` in use.
In our application, for example, this means that if a user has not logged in,
and he tries to add or edit a Wiki page, he will be shown the login form.
Before being allowed to continue on to the add or edit form, he will have to
provide credentials that give him permission to add or edit via this login
form.

Note that we're relying on some additional imports within the bodies of these
views (e.g. ``remember`` and ``forget``). We'll see a rendering of the
entire views.py file a little later here to show you where those come from.
``login()`` is decorated with two decorators:

- a ``@view_config`` decorator which associates it with the
``login`` route and makes it visible when we visit ``/login``,
- a ``@forbidden_view_config`` decorator which turns it into
an :term:`forbidden view`. ``login()`` will be invoked
when a users tries to execute a view callable that
they are not allowed to. For example, if a user has not logged in
and tries to add or edit a Wiki page, he will be shown the
login form before being allowed to continue on.

The order of these two :term:`view configuration` decorators
is unimportant.

``logout()`` is decorated with a ``@view_config`` decorator
which associates it with the ``logout`` route. It will be
invoked when we visit ``/logout``.

Add the ``login.pt`` Template
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Add a ``login.pt`` template to your templates directory. It's
referred to within the login view we just added to ``views.py``.
Create ``tutorial/tutorial/templates/login.pt`` with the following
content:

.. literalinclude:: src/authorization/tutorial/templates/login.pt
:language: xml

The above template is referred to within the login view we just
added to ``views.py``.

Return a logged_in flag to the renderer
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

In order to indicate whether the current user is logged in, we need to change
each of our ``view_page``, ``edit_page`` and ``add_page`` views in
``views.py`` to pass a "logged in" parameter into its template. We'll add
something like this to each view body:
Add the following line to the import at the head of
``tutorial/tutorial/views.py``:

.. code-block:: python
.. literalinclude:: src/authorization/tutorial/views.py
:lines: 11-15
:linenos:
:emphasize-lines: 4
:language: python

from pyramid.security import authenticated_userid
logged_in = authenticated_userid(request)
(Only the highlighted line needs to be added.)

We'll then change the return value of each view that has an associated
``renderer`` to pass the resulting ``logged_in`` value to the
template. For example:
Add a ``logged_in`` parameter to the return value of
``view_page()``, ``edit_page()`` and ``add_page()``,
like this:

.. code-block:: python
:linenos:
:emphasize-lines: 4
return dict(page = context,
return dict(page = page,
content = content,
logged_in = logged_in,
edit_url = edit_url)
edit_url = edit_url,
logged_in = authenticated_userid(request))
(Only the highlighted line needs to be added.)

:meth:`~pyramid.security.authenticated_userid()` will return None
if the user is not authenticated, or some user id it the user
is authenticated.

Add a "Logout" link when logged in
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

We'll also need to change our ``edit.pt`` and ``view.pt`` templates to
display a "Logout" link if someone is logged in. This link will
invoke the logout view.

To do so we'll add this to both templates within the ``<div id="right"
class="app-welcome align-right">`` div:
Open ``tutorial/tutorial/templates/edit.pt`` and
``tutorial/tutorial/templates/view.pt`` and add this within the
``<div id="right" class="app-welcome align-right">`` div:

.. code-block:: xml
<span tal:condition="logged_in">
<a href="${request.application_url}/logout">Logout</a>
</span>
The attribute ``tal:condition="logged_in"`` will make the element be
included when ``logged_in`` is any user id. The link will invoke
the logout view. The above element will not be included if ``logged_in``
is ``None``, such as when a user is not authenticated.

Seeing Our Changes
------------------

Expand All @@ -304,7 +320,7 @@ Our ``views.py`` module will look something like this when we're done:

.. literalinclude:: src/authorization/tutorial/views.py
:linenos:
:emphasize-lines: 8,11-15,24,29,50,54,71,75,85,87-120
:emphasize-lines: 8,11-15,17,24,29,48,52,68,72,80,82-120
:language: python

Our ``edit.pt`` template will look something like this when we're done:
Expand Down
15 changes: 5 additions & 10 deletions docs/tutorials/wiki/src/authorization/tutorial/views.py
Expand Up @@ -9,9 +9,9 @@
)

from pyramid.security import (
authenticated_userid,
remember,
forget,
authenticated_userid,
)

from .security import USERS
Expand Down Expand Up @@ -44,10 +44,8 @@ def check(match):
content = wikiwords.sub(check, content)
edit_url = request.resource_url(context, 'edit_page')

logged_in = authenticated_userid(request)

return dict(page = context, content = content, edit_url = edit_url,
logged_in = logged_in)
logged_in = authenticated_userid(request))

@view_config(name='add_page', context='.models.Wiki',
renderer='templates/edit.pt',
Expand All @@ -66,9 +64,8 @@ def add_page(context, request):
page.__name__ = name
page.__parent__ = context

logged_in = authenticated_userid(request)

return dict(page = page, save_url = save_url, logged_in = logged_in)
return dict(page = page, save_url = save_url,
logged_in = authenticated_userid(request))

@view_config(name='edit_page', context='.models.Page',
renderer='templates/edit.pt',
Expand All @@ -78,11 +75,9 @@ def edit_page(context, request):
context.data = request.params['body']
return HTTPFound(location = request.resource_url(context))

logged_in = authenticated_userid(request)

return dict(page = context,
save_url = request.resource_url(context, 'edit_page'),
logged_in = logged_in)
logged_in = authenticated_userid(request))

@view_config(context='.models.Wiki', name='login',
renderer='templates/login.pt')
Expand Down
15 changes: 5 additions & 10 deletions docs/tutorials/wiki/src/tests/tutorial/views.py
Expand Up @@ -9,9 +9,9 @@
)

from pyramid.security import (
authenticated_userid,
remember,
forget,
authenticated_userid,
)

from .security import USERS
Expand Down Expand Up @@ -44,10 +44,8 @@ def check(match):
content = wikiwords.sub(check, content)
edit_url = request.resource_url(context, 'edit_page')

logged_in = authenticated_userid(request)

return dict(page = context, content = content, edit_url = edit_url,
logged_in = logged_in)
logged_in = authenticated_userid(request))

@view_config(name='add_page', context='.models.Wiki',
renderer='templates/edit.pt',
Expand All @@ -66,9 +64,8 @@ def add_page(context, request):
page.__name__ = name
page.__parent__ = context

logged_in = authenticated_userid(request)

return dict(page = page, save_url = save_url, logged_in = logged_in)
return dict(page = page, save_url = save_url,
logged_in = authenticated_userid(request))

@view_config(name='edit_page', context='.models.Page',
renderer='templates/edit.pt',
Expand All @@ -78,11 +75,9 @@ def edit_page(context, request):
context.data = request.params['body']
return HTTPFound(location = request.resource_url(context))

logged_in = authenticated_userid(request)

return dict(page = context,
save_url = request.resource_url(context, 'edit_page'),
logged_in = logged_in)
logged_in = authenticated_userid(request))

@view_config(context='.models.Wiki', name='login',
renderer='templates/login.pt')
Expand Down
39 changes: 21 additions & 18 deletions docs/tutorials/wiki2/authorization.rst
Expand Up @@ -213,8 +213,8 @@ routes:
Add Login and Logout Views
~~~~~~~~~~~~~~~~~~~~~~~~~~

To our ``views.py`` we'll add a ``login`` view callable which renders a login
form and processes the post from the login form, checking credentials.
We'll add a ``login`` view which renders a login form and processes
the post from the login form, checking credentials.

We'll also add a ``logout`` view callable to our application and
provide a link to it. This view will clear the credentials of the
Expand All @@ -240,24 +240,27 @@ expire an auth ticket cookie.
Now add the ``login`` and ``logout`` views:

.. literalinclude:: src/authorization/tutorial/views.py
:lines: 89-121
:lines: 91-123
:linenos:
:language: python

``login()`` is decorated with two decorators, a
``@view_config`` decorator, which associates it with the ``login``
route and makes it visible when we visit ``/login``,
and a ``@forbidden_view_config`` decorator which turns it into
an :term:`forbidden view`. The forbidden view is
displayed whenever Pyramid or your application raises an
:class:`pyramid.httpexceptions.HTTPForbidden` exception. In this
case we'll show the login form whenever someone attempts
to execute an action which they're not yet
authorized to perform.
``login()`` is decorated with two decorators:

- a ``@view_config`` decorator which associates it with the
``login`` route and makes it visible when we visit ``/login``,
- a ``@forbidden_view_config`` decorator which turns it into
an :term:`forbidden view`. ``login()`` will be invoked
when a users tries to execute a view callable that
they are not allowed to. For example, if a user has not logged in
and tries to add or edit a Wiki page, he will be shown the
login form before being allowed to continue on.

The order of these two :term:`view configuration` decorators
is unimportant.

``logout()`` is decorated with a ``@view_config`` decorator
which associates it with the ``logout`` route. This makes it match when we
visit ``/logout``.
which associates it with the ``logout`` route. It will be
invoked when we visit ``/logout``.

Add the ``login.pt`` Template
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Expand Down Expand Up @@ -291,12 +294,12 @@ like this:

.. code-block:: python
:linenos:
:emphasize-lines: 3
:emphasize-lines: 4
return dict(page = page,
content = content,
logged_in = authenticated_userid(request),
edit_url = edit_url)
edit_url = edit_url,
logged_in = authenticated_userid(request))
(Only the highlighted line needs to be added.)

Expand Down

0 comments on commit fad5003

Please sign in to comment.