当前位置:   article > 正文

django.contrib.auth 登陆注销学习

django.contrib.auth login

备注: 内容基于django1.9版本

auth模块实现功能

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

  • 登录
  • 注销
  • 修改密码
  • 修改密码完成
  • 密码重置
  • 密码重置完成
  • 密码重置验证
  • 密码重置结束
  1. from django.conf.urls import url
  2. from django.contrib.auth import views
  3. # urlpatterns直接是一个list即可
  4. urlpatterns = [
  5. url(r'^login/$', views.login, name='login'),
  6. url(r'^logout/$', views.logout, name='logout'),
  7. url(r'^password_change/$', views.password_change, name='password_change'),
  8. url(r'^password_change/done/$', views.password_change_done, name='password_change_done'),
  9. url(r'^password_reset/$', views.password_reset, name='password_reset'),
  10. url(r'^password_reset/done/$', views.password_reset_done, name='password_reset_done'),
  11. url(r'^reset/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$',
  12. views.password_reset_confirm, name='password_reset_confirm'),
  13. url(r'^reset/done/$', views.password_reset_complete, name='password_reset_complete'),
  14. ]

以下仅对登陆, 注销进行了学习.

login 登录

  1. def login(request, template_name='registration/login.html',
  2. redirect_field_name=REDIRECT_FIELD_NAME,
  3. authentication_form=AuthenticationForm,
  4. extra_context=None):
  5. """
  6. Displays the login form and handles the login action.
  7. """
  8. redirect_to = request.POST.get(redirect_field_name,
  9. request.GET.get(redirect_field_name, ''))
  10. if request.method == "POST":
  11. form = authentication_form(request, data=request.POST)
  12. if form.is_valid():
  13. # Ensure the user-originating redirection url is safe.
  14. if not is_safe_url(url=redirect_to, host=request.get_host()):
  15. redirect_to = resolve_url(settings.LOGIN_REDIRECT_URL)
  16. # Okay, security check complete. Log the user in.
  17. auth_login(request, form.get_user())
  18. return HttpResponseRedirect(redirect_to)
  19. else:
  20. form = authentication_form(request)
  21. current_site = get_current_site(request)
  22. context = {
  23. 'form': form,
  24. redirect_field_name: redirect_to,
  25. 'site': current_site,
  26. 'site_name': current_site.name,
  27. }
  28. if extra_context is not None:
  29. context.update(extra_context)
  30. 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指向地址。
  1. step2 form.is_valid()调用过程
  2. # django.forms.forms.py
  3. class BaseForm(object):
  4. ....
  5. @property
  6. def errors(self):
  7. "Returns an ErrorDict for the data provided for the form"
  8. if self._errors is None:
  9. self.full_clean()
  10. return self._errors
  11. def is_valid(self):
  12. """
  13. Returns True if the form has no errors. Otherwise, False. If errors are
  14. being ignored, returns False.
  15. """
  16. return self.is_bound and not self.errors
  17. def full_clean(self):
  18. """
  19. Cleans all of self.data and populates self._errors and
  20. self.cleaned_data.
  21. """
  22. self._errors = ErrorDict()
  23. if not self.is_bound: # Stop further processing.
  24. return
  25. self.cleaned_data = {}
  26. # If the form is permitted to be empty, and none of the form data has
  27. # changed from the initial data, short circuit any validation.
  28. if self.empty_permitted and not self.has_changed():
  29. return
  30. self._clean_fields()
  31. self._clean_form()
  32. self._post_clean()
  33. def _clean_fields(self):
  34. for name, field in self.fields.items():
  35. # value_from_datadict() gets the data from the data dictionaries.
  36. # Each widget type knows how to retrieve its own data, because some
  37. # widgets split data over several HTML fields.
  38. if field.disabled:
  39. value = self.initial.get(name, field.initial)
  40. else:
  41. value = field.widget.value_from_datadict(self.data, self.files, self.add_prefix(name))
  42. try:
  43. if isinstance(field, FileField):
  44. initial = self.initial.get(name, field.initial)
  45. value = field.clean(value, initial)
  46. else:
  47. value = field.clean(value)
  48. self.cleaned_data[name] = value
  49. ## 如果有clean_filedname方法的话,调用之
  50. if hasattr(self, 'clean_%s' % name):
  51. value = getattr(self, 'clean_%s' % name)()
  52. self.cleaned_data[name] = value
  53. except ValidationError as e:
  54. self.add_error(name, e)
  55. def _clean_form(self):
  56. try:
  57. cleaned_data = self.clean()
  58. except ValidationError as e:
  59. self.add_error(None, e)
  60. else:
  61. if cleaned_data is not None:
  62. self.cleaned_data = cleaned_data
  63. def _post_clean(self):
  64. """
  65. An internal hook for performing additional cleaning after form cleaning
  66. is complete. Used for model validation in model forms.
  67. """
  68. pass
  1. step2 django.contrib.auth.authenticate方法
  2. def load_backend(path):
  3. return import_string(path)()
  4. def _get_backends(return_tuples=False):
  5. backends = []
  6. for backend_path in settings.AUTHENTICATION_BACKENDS:
  7. backend = load_backend(backend_path)
  8. backends.append((backend, backend_path) if return_tuples else backend)
  9. if not backends:
  10. raise ImproperlyConfigured(
  11. 'No authentication backends have been defined. Does '
  12. 'AUTHENTICATION_BACKENDS contain anything?'
  13. )
  14. return backends
  15. def authenticate(**credentials):
  16. """
  17. If the given credentials are valid, return a User object.
  18. """
  19. for backend, backend_path in _get_backends(return_tuples=True):
  20. try:
  21. inspect.getcallargs(backend.authenticate, **credentials)
  22. except TypeError:
  23. # This backend doesn't accept these credentials as arguments. Try the next one.
  24. continue
  25. try:
  26. user = backend.authenticate(**credentials)
  27. except PermissionDenied:
  28. # This backend says to stop in our tracks - this user should not be allowed in at all.
  29. return None
  30. if user is None:
  31. continue
  32. # Annotate the user object with the path of the backend.
  33. user.backend = backend_path
  34. return user
  35. # The credentials supplied are invalid to all backends, fire signal
  36. user_login_failed.send(sender=__name__,
  37. credentials=_clean_credentials(credentials))
  1. step3 django.contrib.auth.login方法
  2. 1. request.user = user
  3. 2. 触发user_logged_in singnal
  4. def login(request, user):
  5. """
  6. Persist a user id and a backend in the request. This way a user doesn't
  7. have to reauthenticate on every request. Note that data set during
  8. the anonymous session is retained when the user logs in.
  9. """
  10. session_auth_hash = ''
  11. if user is None:
  12. user = request.user
  13. if hasattr(user, 'get_session_auth_hash'):
  14. session_auth_hash = user.get_session_auth_hash()
  15. if SESSION_KEY in request.session:
  16. if _get_user_session_key(request) != user.pk or (
  17. session_auth_hash and
  18. request.session.get(HASH_SESSION_KEY) != session_auth_hash):
  19. # To avoid reusing another user's session, create a new, empty
  20. # session if the existing session corresponds to a different
  21. # authenticated user.
  22. request.session.flush()
  23. else:
  24. request.session.cycle_key()
  25. request.session[SESSION_KEY] = user._meta.pk.value_to_string(user)
  26. request.session[BACKEND_SESSION_KEY] = user.backend
  27. request.session[HASH_SESSION_KEY] = session_auth_hash
  28. if hasattr(request, 'user'):
  29. request.user = user
  30. rotate_token(request)
  31. user_logged_in.send(sender=user.__class__, request=request, user=user)
  32. ```
  33. ## logout 注销
  34. ```
  35. @deprecate_current_app
  36. def logout(request, next_page=None,
  37. template_name='registration/logged_out.html',
  38. redirect_field_name=REDIRECT_FIELD_NAME,
  39. extra_context=None):
  40. """
  41. Logs out the user and displays 'You are logged out' message.
  42. """
  43. auth_logout(request)
  44. if next_page is not None:
  45. next_page = resolve_url(next_page)
  46. if (redirect_field_name in request.POST or
  47. redirect_field_name in request.GET):
  48. next_page = request.POST.get(redirect_field_name,
  49. request.GET.get(redirect_field_name))
  50. # Security check -- don't allow redirection to a different host.
  51. if not is_safe_url(url=next_page, host=request.get_host()):
  52. next_page = request.path
  53. if next_page:
  54. # Redirect to this page until the session has been cleared.
  55. return HttpResponseRedirect(next_page)
  56. current_site = get_current_site(request)
  57. context = {
  58. 'site': current_site,
  59. 'site_name': current_site.name,
  60. 'title': _('Logged out')
  61. }
  62. if extra_context is not None:
  63. context.update(extra_context)
  64. return TemplateResponse(request, template_name, context)

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

  1. 登出用户 django.contrib.auth.logout
  2. 1. 出发user_logged_out singnal
  3. 2. request.session.flush()
  4. 3. request.user = AnonymousUser() if hasattr(request, 'user')
  5. def logout(request):
  6. """
  7. Removes the authenticated user's ID from the request and flushes their
  8. session data.
  9. """
  10. # Dispatch the signal before the user is logged out so the receivers have a
  11. # chance to find out *who* logged out.
  12. user = getattr(request, 'user', None)
  13. if hasattr(user, 'is_authenticated') and not user.is_authenticated():
  14. user = None
  15. user_logged_out.send(sender=user.__class__, request=request, user=user)
  16. # remember language choice saved to session
  17. language = request.session.get(LANGUAGE_SESSION_KEY)
  18. request.session.flush()
  19. if language is not None:
  20. request.session[LANGUAGE_SESSION_KEY] = language
  21. if hasattr(request, 'user'):
  22. from django.contrib.auth.models import AnonymousUser
  23. request.user = AnonymousUser()

转载于:https://my.oschina.net/alazyer/blog/737933

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/凡人多烦事01/article/detail/71699
推荐阅读
相关标签
  

闽ICP备14008679号