読者です 読者をやめる 読者になる 読者になる

ログイン状態を保持する

Django

Webアプリケーションのログインの際によく「ログイン状態を保持する」(セッションCookieの有効期限をブラウザ終了時までではなく一定期間に指定する)という選択肢を設けることがある。Djangoの標準の認証機構ではそういったことができないなーと思っていて、でも、Pinaxにはあるだろうと考えたら、やっぱりあった。pinaxのlocal_apps/accountを使えばよさげ。

以下は、pinax/local_apps/account/forms.pyからの抜粋。

class LoginForm(forms.Form):

    username = forms.CharField(label=_("Username"), max_length=30, widget=forms.TextInput())
    password = forms.CharField(label=_("Password"), widget=forms.PasswordInput(render_value=False))
    remember = forms.BooleanField(label=_("Remember Me"), help_text=_("If checked you will stay logged in for 3 weeks"), required=False)

    user = None

    def clean(self):
        if self._errors:
            return
        user = authenticate(username=self.cleaned_data["username"], password=self.cleaned_data["password"])
        if user:
            if user.is_active:
                self.user = user
            else:
                raise forms.ValidationError(_("This account is currently inactive."))
        else:
            raise forms.ValidationError(_("The username and/or password you specified are not correct."))
        return self.cleaned_data

    def login(self, request):
        if self.is_valid():
            login(request, self.user)
            request.user.message_set.create(message=ugettext(u"Successfully logged in as %(username)s.") % {'username': self.user.username})
            if self.cleaned_data['remember']:
                request.session.set_expiry(60 * 60 * 24 * 7 * 3)
            else:
                request.session.set_expiry(0)
            return True
        return False

この実装のキモは、

  • validate(form.clean())したときに該当のユーザをFormオブジェクト・インスタンスにそのユーザを保持しておく(該当するユーザがいなければValidationErrorにする)
  • LoginFormにloginメソッドを実装する

ことか。コードを見れば「あぁ、なるほどー」と思うが、これは自分では結構思いつかなかった(pinax侮りがたし!)。上記のコードでは、「ログイン状態を保存する」を選択したときには、Cookieの有効期限を"60 * 60 * 24 * 7 * 3"(3週間)に指定しているが、この辺は好みとアプリケーションの仕様に対する要請に応じて自由に変更したいところかな。

僕の場合、

  • authenticate関数はDjango標準のものを使っていない

という事情があるので、そのままは使えないけど、かなり参考になった。「SESSION_COOKIE_AGEでしかセッションCookieの有効期限を指定できないのはDjangoの重大な欠陥」と思っていたけど、いつのまにか、set_expiryというメソッドが実装されているのね。

ともあれ、普通にDjangoアプリケーションを作っている人は、django.contrib.authの認証機構ではなく、pinaxの認証機構をチェックしてみるといいんじゃないかな。