Changes between Initial Version and Version 1 of CookBookShortcutsOpenIDAuthentication


Ignore:
Timestamp:
Apr 16, 2006, 9:55:12 PM (19 years ago)
Author:
djangoproject.com@…
Comment:

New page; editing will be required.

Legend:

Unmodified
Added
Removed
Modified
  • CookBookShortcutsOpenIDAuthentication

    v1 v1  
     1This example requires that the Python OpenID library is already installed.  You can find that at http://www.openidenabled.com/openid/libraries/python.
     2
     3In order to support [http://openid.net/ OpenID] authentication, you'll only need two views.  They can be linked to whatever URLs you like, but I've picked "/openid/" and "/openid/process/", with the following entries in urls.py:
     4
     5{{{
     6#!python
     7(r'^openid/$', 'myproject.openid.openid_form'),
     8(r'^openid/process/(?P<token>.*/$', 'myproject.openid.process'),
     9}}}
     10
     11The views need to make use of an OpenID consumer, which I initialize when the views.py file is loaded.  The below makes of an additional setting that I placed into settings.py, a constant to indicate where the OpenID library should store its state information.
     12
     13{{{
     14#!python
     15def initializeOpenID ():
     16    store = openid.store.filestore.FileOpenIDStore (OPENID_DATASTORE_PATH)
     17    global OID_CONSUMER
     18    OID_CONSUMER = openid.consumer.consumer.OpenIDConsumer (store)
     19
     20initializeOpenID ()
     21}}}
     22
     23You'll need one view to allow the user to specify an OpenID URL to authenticate.  The following method uses another settings.py addition called SITE_TOP_URL.  (If there's a better way to get or specify this information, I'd like to know.)
     24
     25{{{
     26#!python
     27@login_required
     28def openid_form (request):
     29    class OpenIDManipulator (formfields.Manipulator):
     30        def __init__ (self):
     31            self.fields = (formfields.TextField (field_name="url", length=30, maxlength=50, is_required=True),)
     32    manipulator = OpenIDManipulator ()
     33    errors = dict ()
     34    if request.POST:
     35        new_data = request.POST.copy ()
     36        openid_url = request.POST['url']
     37 
     38        if not openid_url:
     39            errors['url'] = ['You must enter an OpenID URL.']
     40 
     41        if len (errors) == 0:
     42            status, info = OID_CONSUMER.beginAuth (openid_url)
     43 
     44            if status == openid.consumer.consumer.HTTP_FAILURE:
     45                fmt = 'Failed to retrieve <q>%s</q>' + ': %s' % status
     46                errors['url'] = fmt % (cgi.escape (openid_url),)
     47            elif status == openid.consumer.consumer.PARSE_ERROR:
     48                fmt = 'Could not find OpenID information in <q>%s</q>'
     49                errors['url'] = fmt % (cgi.escape (openid_url),)
     50            elif status == openid.consumer.consumer.SUCCESS:
     51                return_to = SITE_TOP_URL + '/openid/process/%s' % info.token
     52                redirect_url = OID_CONSUMER.constructRedirect (info, return_to, trust_root=SITE_TOP_URL)
     53                return HttpResponseRedirect (redirect_url)
     54            else:
     55                errors['url'] = ["Shouldn't happen"]
     56    else:
     57        new_data = {}
     58        errors = new_data = {}
     59    form = formfields.FormWrapper (manipulator, new_data, errors)
     60    return render_to_response ('openid/openid', {'form': form})
     61}}}
     62
     63And another to handle the result of the authentication:
     64
     65{{{
     66#!python
     67@login_required
     68def process (request, token=None):
     69    status, info = OID_CONSUMER.completeAuth (token, request.GET)
     70
     71    if status == openid.consumer.consumer.FAILURE and info:
     72        message = 'Verification of "%s" failed.' % cgi.escape (info)
     73    elif status == openid.consumer.consumer.SUCCESS:
     74        if info:
     75            message = 'Successfully verified "%s".' % cgi.escape (info)
     76        else:
     77            message = 'Verification cancelled.'
     78    else:
     79        message = 'Verification failed.'
     80
     81    request.user.add_message (message)
     82    return HttpResponseRedirect ('/')
     83}}}
     84
     85Obviously, at this point you'll want to do something useful such as making a record of the correspondence between the current user and the provided OpenID URL, and then to allow an OpenID authentication to authenticate the corresponding native user.  (I haven't added these in the current example, but they could both be accomplished by edits to the process() method above.)
     86
     87Finally, to allow the foregoing to actually work, you'll need some import statements at the top of your views.py:
     88
     89{{{
     90#!python
     91import cgi
     92import openid
     93import openid.store. filestore
     94import openid.consumer.consumer
     95from myproject.settings import OPENID_DATASTORE_PATH,SITE_TOP_URL
     96global OID_CONSUMER
     97}}}
     98
     99... and have a form for the user to input their URL, with something like the following in it:
     100
     101{{{
     102<form method="post" action=".">
     103 
     104<table>
     105<tr><th><label for="id_url">OpenID URL:</label></th><td>{{ form.url }}</td>
     106<td class="formError">{% if form.url.errors %}{{ form.url.errors|join:", " %}{% endif %}</td></tr>
     107</table>
     108 
     109<input type="submit" value="Authenticate"/>
     110 
     111</form>
     112}}}
Back to Top