文档章节

django.contrib.auth登陆注销学习

alazyer
 alazyer
发布于 2017/05/23 16:17
字数 1337
阅读 134
收藏 0

auth模块实现功能

通过入口url.py文件中定义的urlpatterns可以看出,auth模块共定义了8个url,分别用于:

  • 登录
  • 注销
  • 修改密码
  • 修改密码完成
  • 密码重置
  • 密码重置完成
  • 密码重置验证
  • 密码重置结束
from django.conf.urls import url
from django.contrib.auth import views

# urlpatterns直接是一个list即可
urlpatterns = [
    url(r'^login/$', views.login, name='login'),
    url(r'^logout/$', views.logout, name='logout'),
    url(r'^password_change/$', views.password_change, name='password_change'),
    url(r'^password_change/done/$', views.password_change_done, name='password_change_done'),
    url(r'^password_reset/$', views.password_reset, name='password_reset'),
    url(r'^password_reset/done/$', views.password_reset_done, name='password_reset_done'),
    url(r'^reset/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$',
        views.password_reset_confirm, name='password_reset_confirm'),
    url(r'^reset/done/$', views.password_reset_complete, name='password_reset_complete'),
]

这篇文章主要学习登录和注销相关代码

login 登录

def login(request, template_name='registration/login.html',
          redirect_field_name=REDIRECT_FIELD_NAME,
          authentication_form=AuthenticationForm,
          extra_context=None):
    """
    Displays the login form and handles the login action.
    """
    redirect_to = request.POST.get(redirect_field_name,
                                   request.GET.get(redirect_field_name, ''))

    if request.method == "POST":
        form = authentication_form(request, data=request.POST)
        if form.is_valid():

            # Ensure the user-originating redirection url is safe.
            if not is_safe_url(url=redirect_to, host=request.get_host()):
                redirect_to = resolve_url(settings.LOGIN_REDIRECT_URL)

            # Okay, security check complete. Log the user in.
            auth_login(request, form.get_user())

            return HttpResponseRedirect(redirect_to)
    else:
        form = authentication_form(request)

    current_site = get_current_site(request)

    context = {
        'form': form,
        redirect_field_name: redirect_to,
        'site': current_site,
        'site_name': current_site.name,
    }
    if extra_context is not None:
        context.update(extra_context)

    return TemplateResponse(request, template_name, context)

登录处理视图函数依据功能分为:

  • 展示登录页面供用户提供认证信息进行登录操作(request.method == "GET")
  • 对用户提交的认证信息进行认证,并做出相应反映(request.method == "POST")

request.method == "GET"

  1. 实例化一个authentication_form实例(通过传入request将request绑定到form实例上),供用户输入认证信息
  2. 获取站点信息,供页面显示
  3. 生成context,并使用关键词参数extra_context进行拓展
  4. 返回页面(TemplateResponse)

此场景处理逻辑较简单

request.method == "POST"

  1. 通过获取到的用户数据(request.POST)实例化authentication_form
  2. 判断用户输入数据是否有效合理(检查是否有输入传入;并且调用full_clean方法来进行验证)。默认的AuthenticationForm中的clean方法中会调用django.contrib.auth.authenticate方法对用户提供的认证信息进行校验。而authenticate方法会遍历settings中定义的AUTHENTICATION_BACKENDS模块,并调用模块的authenticate方法进行认证,直到成功,否则出发user_login_failed singnal
  3. 调用django.contrib.auth.login方法使得用户登录成功,并返回HttpResponseRedirect响应,重定向到redirect_field_name指向地址。
step2 form.is_valid()调用过程
# django.forms.forms.py
class BaseForm(object):
    ....
    @property
    def errors(self):
        "Returns an ErrorDict for the data provided for the form"
        if self._errors is None:
            self.full_clean()
        return self._errors

    def is_valid(self):
        """
        Returns True if the form has no errors. Otherwise, False. If errors are
        being ignored, returns False.
        """
        return self.is_bound and not self.errors
    
    def full_clean(self):
        """
        Cleans all of self.data and populates self._errors and
        self.cleaned_data.
        """
        self._errors = ErrorDict()
        if not self.is_bound:  # Stop further processing.
            return
        self.cleaned_data = {}
        # If the form is permitted to be empty, and none of the form data has
        # changed from the initial data, short circuit any validation.
        if self.empty_permitted and not self.has_changed():
            return

        self._clean_fields()
        self._clean_form()
        self._post_clean()
        
    def _clean_fields(self):
        for name, field in self.fields.items():
            # value_from_datadict() gets the data from the data dictionaries.
            # Each widget type knows how to retrieve its own data, because some
            # widgets split data over several HTML fields.
            if field.disabled:
                value = self.initial.get(name, field.initial)
            else:
                value = field.widget.value_from_datadict(self.data, self.files, self.add_prefix(name))
            try:
                if isinstance(field, FileField):
                    initial = self.initial.get(name, field.initial)
                    value = field.clean(value, initial)
                else:
                    value = field.clean(value)
                self.cleaned_data[name] = value
                ## 如果有clean_filedname方法的话,调用之
                if hasattr(self, 'clean_%s' % name):
                    value = getattr(self, 'clean_%s' % name)()
                    self.cleaned_data[name] = value
            except ValidationError as e:
                self.add_error(name, e)

    def _clean_form(self):
        try:
            cleaned_data = self.clean()
        except ValidationError as e:
            self.add_error(None, e)
        else:
            if cleaned_data is not None:
                self.cleaned_data = cleaned_data

    def _post_clean(self):
        """
        An internal hook for performing additional cleaning after form cleaning
        is complete. Used for model validation in model forms.
        """
        pass
step2 django.contrib.auth.authenticate方法
def load_backend(path):
    return import_string(path)()

def _get_backends(return_tuples=False):
    backends = []
    for backend_path in settings.AUTHENTICATION_BACKENDS:
        backend = load_backend(backend_path)
        backends.append((backend, backend_path) if return_tuples else backend)
    if not backends:
        raise ImproperlyConfigured(
            'No authentication backends have been defined. Does '
            'AUTHENTICATION_BACKENDS contain anything?'
        )
    return backends

def authenticate(**credentials):
    """
    If the given credentials are valid, return a User object.
    """
    for backend, backend_path in _get_backends(return_tuples=True):
        try:
            inspect.getcallargs(backend.authenticate, **credentials)
        except TypeError:
            # This backend doesn't accept these credentials as arguments. Try the next one.
            continue

        try:
            user = backend.authenticate(**credentials)
        except PermissionDenied:
            # This backend says to stop in our tracks - this user should not be allowed in at all.
            return None
        if user is None:
            continue
        # Annotate the user object with the path of the backend.
        user.backend = backend_path
        return user

    # The credentials supplied are invalid to all backends, fire signal
    user_login_failed.send(sender=__name__,
            credentials=_clean_credentials(credentials))
step3 django.contrib.auth.login方法

1. request.user = user
2. 触发user_logged_in singnal

def login(request, user):
    """
    Persist a user id and a backend in the request. This way a user doesn't
    have to reauthenticate on every request. Note that data set during
    the anonymous session is retained when the user logs in.
    """
    session_auth_hash = ''
    if user is None:
        user = request.user
    if hasattr(user, 'get_session_auth_hash'):
        session_auth_hash = user.get_session_auth_hash()

    if SESSION_KEY in request.session:
        if _get_user_session_key(request) != user.pk or (
                session_auth_hash and
                request.session.get(HASH_SESSION_KEY) != session_auth_hash):
            # To avoid reusing another user's session, create a new, empty
            # session if the existing session corresponds to a different
            # authenticated user.
            request.session.flush()
    else:
        request.session.cycle_key()
    request.session[SESSION_KEY] = user._meta.pk.value_to_string(user)
    request.session[BACKEND_SESSION_KEY] = user.backend
    request.session[HASH_SESSION_KEY] = session_auth_hash
    if hasattr(request, 'user'):
        request.user = user
    rotate_token(request)
    user_logged_in.send(sender=user.__class__, request=request, user=user)

logout 注销

@deprecate_current_app
def logout(request, next_page=None,
           template_name='registration/logged_out.html',
           redirect_field_name=REDIRECT_FIELD_NAME,
           extra_context=None):
    """
    Logs out the user and displays 'You are logged out' message.
    """
    auth_logout(request)

    if next_page is not None:
        next_page = resolve_url(next_page)

    if (redirect_field_name in request.POST or
            redirect_field_name in request.GET):
        next_page = request.POST.get(redirect_field_name,
                                     request.GET.get(redirect_field_name))
        # Security check -- don't allow redirection to a different host.
        if not is_safe_url(url=next_page, host=request.get_host()):
            next_page = request.path

    if next_page:
        # Redirect to this page until the session has been cleared.
        return HttpResponseRedirect(next_page)

    current_site = get_current_site(request)
    context = {
        'site': current_site,
        'site_name': current_site.name,
        'title': _('Logged out')
    }
    if extra_context is not None:
        context.update(extra_context)

    return TemplateResponse(request, template_name, context)

实现了登出用户,并跳转到指定(next_page或者request.GET, request.POST中携带的redicted_field_name)页面功能

登出用户 django.contrib.auth.logout

1. 出发user_logged_out singnal
2. request.session.flush()
3. request.user = AnonymousUser() if hasattr(request, 'user')

def logout(request):
    """
    Removes the authenticated user's ID from the request and flushes their
    session data.
    """
    # Dispatch the signal before the user is logged out so the receivers have a
    # chance to find out *who* logged out.
    user = getattr(request, 'user', None)
    if hasattr(user, 'is_authenticated') and not user.is_authenticated():
        user = None
    user_logged_out.send(sender=user.__class__, request=request, user=user)

    # remember language choice saved to session
    language = request.session.get(LANGUAGE_SESSION_KEY)

    request.session.flush()

    if language is not None:
        request.session[LANGUAGE_SESSION_KEY] = language

    if hasattr(request, 'user'):
        from django.contrib.auth.models import AnonymousUser
        request.user = AnonymousUser()

© 著作权归作者所有

alazyer
粉丝 5
博文 68
码字总数 35105
作品 0
程序员
私信 提问
Pycharm上Django的使用 Day11

注销和注册 1.注销 对于注销,我们不创建用于注销的页面,只需单击一个链接就能注销并返回到主页 1>创建注销的URL模式 这个URL模式将请求发送给视图函数logout_view() 2>编写视图函数logout_...

不会TC的猫
2018/11/22
0
0
对django 认证模块的学习

07-05-01) django通过以下中间件提供对认证的支持'django.contrib.sessions.middleware.SessionMiddleware' 'django.contrib.auth.middleware.AuthenticationMiddleware' 应用模块为'django......

凌晨4点半
2013/08/08
214
0
Django auth认证模块

  【11】Django auth认证模块      一、auth模块      from django.contrib import auth      1 、authenticate() :验证用户输入的用户名和密码是否相同      提供了用户...

SEOwhywhy
02/16
0
0
django.contrib.auth 登陆注销学习

备注: 内容基于django1.9版本 auth模块实现功能 通过入口url.py文件中定义的urlpatterns可以看出,auth模块共定义了8个url,分别用于: 登录 注销 修改密码 修改密码完成 密码重置 密码重置...

alazyer
2016/08/25
15
0
3.0注销有bug?

比如说 我新建有一个菜单,设置了角色 ,某个用户只能访问这个菜单,访问不了别的菜单,超级管理员则全部可以看到,现在IE11(其他没试过)下,如果是采用关闭浏览器,然后用这个特定用户登陆...

chulaihunde
2014/09/10
206
3

没有更多内容

加载失败,请刷新页面

加载更多

读书replay《maven实战》.1.20190526

前情提要 maven这个工具用了好久了,但是一直都用的迷迷糊糊的,没有对它进行过系统性的学习,只是知道一些常用的功能怎么实现,所以20190516这一天我从JD购买了徐晓斌老师所著的《maven实战...

wanxiangming
29分钟前
0
0
真实项目案例实战——【状态设计模式】使用场景

什么是状态模式 状态模式允许一个对象在其内部状态改变的时候改变其行为。这个对象看上去就像是改变了它的类一样。 状态模式应用场景 1.一个对象的行为取决于它的状态,并且它必须在运行时刻根...

须臾之余
36分钟前
0
0
Java 实现把字符串转换成整数【底层实现】

https://blog.csdn.net/zl18310999566/article/details/80263396

qimh
39分钟前
0
0
IDEA的debugger

1、win下节省内存空间 3、条件断点

一只小青蛙
50分钟前
3
0
炸!亿级数据DB秒级平滑扩容

一步一步,娓娓道来。 一般来说,并发量大,吞吐量大的互联网分层架构是怎么样的? 数据库上层都有一个微服务,服务层记录“业务库”与“数据库实例配置”的映射关系,通过数据库连接池向数据...

编程SHA
55分钟前
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部