On Tue, 2005-08-30 at 04:24 -0700, [EMAIL PROTECTED] wrote:
> Hi All
> 
> Just starting with django and have very quickly got to the point where
> I can set out a simple little app.
> 
> The next thing I need to be able to do is implement user
> authentication. Nothing too fancy just a basic one log in and you can
> do everything type set up.
> 
> My question is what is the best way to go about this? Where should my
> security checks go, in the view? in the model?

A little bit of both.  I'm doing a multi-user feed reader right now
(will be publicly released when I'm happy with it), so I've managed to
get this working.  Basically you want a user model that can handle its
own authentication (it can be entirely database-backed, or it can be a
cache of some other source, such as ldap).

Then you need a login view, which will check authentication and if
successful, store the user_id in the session, and you need something
(probably a decorator) to check that the user is logged in where
required.  Here's the login-relevant stuff from my app; some of which is
copied more-or-less-directly from django's admin framework:

models/engulf.py:

class User(meta.Model):
    username = meta.CharField('Username',  maxlength=64, unique=True)
    password = meta.CharField('Password', maxlength=64)
    feed = meta.ManyToManyField(Feed, filter_interface=meta.VERTICAL,
                         null=True, blank=True)
    class META:
        admin = meta.Admin()
    def __repr__(self):
        return self.username
    def check_password(self,password):
        if password == self.password:
            return True
        else:
            return False

views/engulf.py:


class LoginManipulator(formfields.Manipulator):
    def __init__(self):
        self.fields = (
            formfields.TextField(field_name="username",
                                 length=30, maxlength=64,
                                 is_required=True,
                                 validator_list=[self.check_login]),
            formfields.PasswordField(field_name="password",
                                     length=30, maxlength=64,
                                     is_required=True),
            )
    def check_login(self, field_data, all_data):
        username = all_data['username']
        password = all_data['password']
        try:
            u = users.get_object(username__exact=username)
            if u.check_password(password):
                return True
            else:
                raise validators.ValidationError("Invalid username/password.")
        except users.UserDoesNotExist:
            raise validators.ValidationError("Invalid username/password.")
def login(request):
    manipulator = LoginManipulator()
    if request.POST:
        new_data = request.POST.copy()
        errors = manipulator.get_validation_errors(new_data)
        if not errors:
            # successful login
            u = users.get_object(username__exact=request.POST['username'])
            request.session['user_id'] = u.id
            if request.GET:
                try:
                    next = self.request.GET['next']
                    return HttpResponseRedirect(next)
                except KeyError:
                    pass
            return HttpResponseRedirect('/engulf/')
    else:
        new_data = errors = {}
    form = formfields.FormWrapper(manipulator, new_data, errors)
    t = template_loader.get_template("engulf/login")
    c = Context(request, { 'form': form,} )
    return HttpResponse(t.render(c))
    
def logout(request):
    try:
        del request.session['user_id']
    except KeyError:
        pass
    manipulator = LoginManipulator()
    new_data = errors = {}
    form = formfields.FormWrapper(manipulator, new_data, errors)
    t = template_loader.get_template("engulf/login")
    c = Context(request, {
            'form': form,
            'from_logout': "You have successfully logged out."
            } )
    return HttpResponse(t.render(c))

And views/util.py:

def redirect_to_login(next):
    "Redirects the user to the login page, passing the given 'next' page"
    response = HttpResponseRedirect('/engulf/accounts/login/?%s=%s' %
                                (REDIRECT_FIELD_NAME, next))
    response['Pragma'] = "no cache"
    response['Cache-Control'] = "no-cache"
    return response

# decorators
def login_required(view_func):
    """
    Decorator for views that checks that the user is logged in, redirecting
    to the log-in page if necessary.
    """
    def _checklogin(request, *args, **kwargs):
        try:
            user_id = request.session['user_id']
            u = users.get_object(id__exact=user_id)
            if user_id:
                return view_func(request, *args, **kwargs)
            else:
                return redirect_to_login(request.path)
        except (KeyError, users.UserDoesNotExist):
            return redirect_to_login(request.path)
    return _checklogin


A typical view function will be decorated with login_required like so
(as I'm using python 2.3):

def view(req):
    blah blah blah...
view = util.login_required(blah)

> Anyone point me in the right direction? Or even a breif explanation of
> how django's admin authentcation works might get me going.

I arrived at this solution by looking at the anonymous session
documentation and the admin code.  If my code samples don't help, you
might want to look there, too.

Good luck!

-- 
+----------------------------------------------------------------+
| Jason F. McBrayer                         [EMAIL PROTECTED]  |
|  "If you wish to make Pythocles wealthy, don't give him more   |
|   money; rather, reduce his desires."            -- Epicurus   |

Reply via email to