zoukankan      html  css  js  c++  java
  • Django用户认证系统(二)Web请求中的认证

    在每个Web请求中都提供一个 request.user 属性来表示当前用户。如果当前用户未登录,则该属性为AnonymousUser的一个实例,反之,则是一个User实例。

    你可以通过is_authenticated()来区分,例如:

    if request.user.is_authenticated():
        # Do something for authenticated users.
    else:
        # Do something for anonymous users.
    

    登陆login

    login()

    登陆函数,需要一个HttpRequest对象和一个User对象作参数。login()使用django的session框架,将User的id存储在session中。

    同时使用authenticate()和login():

    from django.contrib.auth import authenticate, login
    
    def my_view(request):
        username = request.POST['username']
        password = request.POST['password']
        user = authenticate(username=username, password=password)
        if user is not None:
            if user.is_active:
                login(request, user)
                # Redirect to a success page.
            else:
                # Return a 'disabled account' error message
        else:
            # Return an 'invalid login' error message.
    

    如果不知道密码,login方法:

    user=MyUser.objects.get(...)
    user.backend = 'django.contrib.auth.backends.ModelBackend'
    login(request,user)

    退出登录logout

    logout()

    使用HttpRequest对象为参数,无返回值。例如:

    from django.contrib.auth import logout
    
    def logout_view(request):
        logout(request)
        # Redirect to a success page.
    

    限制访问

    The raw way

    使用 request.user.is_authenticated() 

    再定向:

    from django.shortcuts import redirect
    
    def my_view(request):
        if not request.user.is_authenticated():
            return redirect('/login/?next=%s' % request.path)
        # ...
    

    或者:

    from django.shortcuts import render
    
    def my_view(request):
        if not request.user.is_authenticated():
            return render(request, 'myapp/login_error.html')
        # ...
    

    使用装饰器login_required

    login_required([redirect_field_name=REDIRECT_FIELD_NAME, login_url=None]

    from django.contrib.auth.decorators import login_required
    
    @login_required
    def my_view(request):
        ...
    

    如果用户未登录,则重定向到 settings.LOGIN_URL,并将现在的url相对路径构成一个next做key的查询字符对附加到 settings.LOGIN_URL后面去:

    /accounts/login/?next=/polls/3/.
    

    query字符对的key默认为next,也可以自己命名:

    from django.contrib.auth.decorators import login_required
    
    @login_required(redirect_field_name='my_redirect_field')
    def my_view(request):
        ...
    

    也可以自己定义login_url:

    from django.contrib.auth.decorators import login_required
    
    @login_required(login_url='/accounts/login/')
    def my_view(request):
        ...
    

    urls.py中需定义:

    (r'^accounts/login/$', 'django.contrib.auth.views.login'),
    

    测试登录用户

    例如,要检测用户的email:

    def my_view(request):
        if not '@example.com' in request.user.email:
            return HttpResponse("You can't vote in this poll.")
        # ...
    

    可以用装饰器:

    from django.contrib.auth.decorators import user_passes_test
    
    def email_check(user):
        return '@example.com' in user.email
    
    @user_passes_test(email_check)
    def my_view(request):
        ...
    

    也可以改变login_url:

    @user_passes_test(email_check, login_url='/login/')
    def my_view(request):
        ...
    

    认证Views

    当然,我们可以自己定义一些登陆,登出,密码管理的view 函数,而且也更加方便。

    不过也可以学习下Django内置的views。

    Django没有为认证views提供缺省模板,however the template context is documented for each view below.

    所有内置views都返回一个TemplateResponse实例,可以让你很方便的定制response数据。

    https://github.com/django/django/blob/master/django/contrib/auth/views.py

    多数的内置认证views都提供一个URL名称以便使用。

    login(request[, template_name, redirect_field_name, authentication_form,current_app,extra_context])

    源码:

    def login(request, template_name='registration/login.html',
              redirect_field_name=REDIRECT_FIELD_NAME,
              authentication_form=AuthenticationForm,
              current_app=None, 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,
                                current_app=current_app)
    

    URL name: login

    参数:

    template_name: 默认的登陆模板.默认为registration/login.html.
    redirect_field_name: 重定向的name,默认为next.
    authentication_form: 默认Form. Defaults to AuthenticationForm.
    current_app: A hint indicating which application contains the current view. See the namespaced URL resolution strategy for more information.
    extra_context: 添加到默认context data中的额外数据,为字典。

    django.contrib.auth.views.login does:

    如果通过GET访问, 将显示登录表单,可以将其内容POST到相同的URL上。
    如果通过POST访问,它首先会尝试登录,如果成功,view就重定向到next指定的的链接。如果next 未设置,则重定向到settings.LOGIN_REDIRECT_URL(一般缺省值为accounts/profile/)。如果登录失败,则再次显示登录表单。

    需要用户自己来提供login的html模板,缺省是registration/login.html 。这个模板将传递4个模板上下文变量:

    form: 一个表单对象AuthenticationForm.
    next: 登录成功后的重定向链接,可以包含一个query string中。
    site: 当前网站,根据 SITE_ID 设置。如果你并没有安装site框架,这个变量将设定为一个 RequestSite实例,它从当前 HttpRequest中取得站点名和域名。
    site_name: 是 site.name的一个别名。如果你没有安装site框架,它将会被设为 request.META['SERVER_NAME']的值。

    如果你不想调用registration/login.html模板,你可以在URLconf中设定特定的view参数来传递template_name参数。

    (r'^accounts/login/$', 'django.contrib.auth.views.login', {'template_name': 'myapp/login.html'}),

    你也可以自己指定重定向链接字段名,通过redirect_field_name 参数。默认的字段名为next.

    下面是registration/login.html 模板的原始状态,它假定你有一个base.html模板(其中有content block的定义。

    {% extends "base.html" %}
    
    {% block content %}
    
    {% if form.errors %}
    <p>Your username and password didn't match. Please try again.</p>
    {% endif %}
    
    <form method="post" action="{% url 'django.contrib.auth.views.login' %}">
    {% csrf_token %}
    <table>
    <tr>
        <td>{{ form.username.label_tag }}</td>
        <td>{{ form.username }}</td>
    </tr>
    <tr>
        <td>{{ form.password.label_tag }}</td>
        <td>{{ form.password }}</td>
    </tr>
    </table>
    
    <input type="submit" value="login" />
    <input type="hidden" name="next" value="{{ next }}" />
    </form>
    
    {% endblock %}

    如果自己定制认证系统,可以通过 authentication_form 参数把自定义的认证表单传给login view。该表单的__init__ 方法应该有一个request 的参数,并提供一个 get_user 方法来返回认证后的User对象。

    logout(request[, next_page, template_name, redirect_field_name, current_app,extra_context])

    登出用户.

    URL name: logout

    可选参数:

    next_page: 注销后的重定向链接.

    logout_then_login(request[, login_url, current_app, extra_context])

    注销用户然后重定向到登录链接.

    可选参数:

    login_url: 登陆页面的重定向链接,缺省值为 settings.LOGIN_URL。

    password_change(request[, template_name, post_change_redirect,password_change_form,current_app, extra_context])

    允许用户修改密码.

    URL name: password_change

    可选参数 Optional arguments:

    template_name: 模板名,缺省值为registration/password_change_form.html 。
    post_change_redirect: 重定向链接。
    password_change_form: 自定义的密码修改表单,包括一个user 参数。缺省值为PasswordChangeForm.

    password_change_done(request[, template_name,current_app, extra_context])

    用户修改密码后的页面.

    URL name: password_change_done

    可选参数 Optional arguments:

    template_name: 模板名称,缺省为registration/password_change_done.html.

    password_reset(request[, is_admin_site, template_name, email_template_name, password_reset_form, token_generator, post_reset_redirect, from_email, current_app, extra_context, html_email_template_name])

    向用户发送邮件,内含一个一次性链接,来让用户重设密码。

    如果提供的邮箱不存在,则不会发送。

    URL name: password_reset

    可选参数 Optional arguments:

    template_name: 模板名称,缺省值为registration/password_reset_form.html。
    email_template_name: 用来生成带充值链接email的模板名称,缺省值为registration/password_reset_email.html。
    subject_template_name: 用来生成邮件主题的模板名称,缺省值为 registration/password_reset_subject.txt。
    password_reset_form: 重设密码的表单,缺省值为 PasswordResetForm.

    token_generator: 检查一次性链接的类实例,缺省值为default_token_generator, 其类为django.contrib.auth.tokens.PasswordResetTokenGenerator.

    post_reset_redirect: 密码重置后的重定向链接.

    from_email: 邮件地址,缺省值为DEFAULT_FROM_EMAIL.

    current_app: A hint indicating which application contains the current view. See the namespaced URL resolution strategy for more information.
    extra_context: A dictionary of context data that will be added to the default context data passed to the template.
    html_email_template_name: The full name of a template to use for generating a text/html multipart email with the password reset link. By default, HTML email is not sent.

    示例: registration/password_reset_email.html (email内容模板):

    Someone asked for password reset for email {{ email }}. Follow the link below:
    {{ protocol}}://{{ domain }}{% url 'password_reset_confirm' uidb64=uid token=token %}

    password_reset_done(request[, template_name])

    显示用户选择发送密码重置邮件后的页面。如果 password_reset() view中没有显式指定post_reset_redirect链接时,则直接调用本view。

    password_reset_confirm(request[, uidb36, token, template_name, token_generator,set_password_form, post_reset_redirect,current_app, extra_context])

    显示输入新密码的表单.

    password_reset_complete(request[, template_name, current_app, extra_context])

    重置密码成功后的表单。

    Helper functions

    redirect_to_login(next[, login_url, redirect_field_name])

    重定向到登录页面,登录成功后的在重定向到另一链接。.

    参数:

    next: 登录成功后的链接.

    login_url: 登陆页面链接,默认缺省值:settings.LOGIN_URL。

    redirect_field_name: 重定向字段名称,缺省值为next。

    内置表单 Built-in forms

    class AdminPasswordChangeForm

    admin后台的用户密码修改表单

    class AuthenticationForm

    登录表单。

    方法confirm_login_allowed(user)

    例如,允许所有的users登陆,不管is_active属性:

    from django.contrib.auth.forms import AuthenticationForm
    
    class AuthenticationFormWithInactiveUsersOkay(AuthenticationForm):
        def confirm_login_allowed(self, user):
            pass

    或者只允许活跃用户登陆:

    class PickyAuthenticationForm(AuthenticationForm):
        def confirm_login_allowed(self, user):
            if not user.is_active:
                raise forms.ValidationError(
                    _("This account is inactive."),
                    code='inactive',
                )
            if user.username.startswith('b'):
                raise forms.ValidationError(
                    _("Sorry, accounts starting with 'b' aren't welcome here."),
                    code='no_b_users',
                )
    

    class PasswordChangeForm

    修改密码表单.

    class PasswordResetForm

    密码重置表单.

    class SetPasswordForm

    密码设置表单.

    class UserChangeForm

    admin后台的用户信息和权限修改表单.

    class UserCreationForm

    用户创建表单.

    模板中的认证信息 Authentication data in templates

    当前登录用户及其权限可以在模板变量中取得,通过使用RequestContext.

    Users
    在渲染模板 RequestContext时,当前的登录用户无论是User实例还是AnonymousUser 实例均保存在模板变量 {{ user }}:

    {% if user.is_authenticated %}
        <p>Welcome, {{ user.username }}. Thanks for logging in.</p>
    {% else %}
        <p>Welcome, new user. Please log in.</p>
    {% endif %}

    如果未使用 RequestContext,则此变量不存在。

    使用RequestContext:

    from django.shortcuts import render_to_response
    from django.template import RequestContext
    
    def some_view(request):
        # ...
        return render_to_response('my_template.html',
                                  my_data_dictionary,
                                  context_instance=RequestContext(request))
    

      

  • 相关阅读:
    PHP 快速实现大文件上传
    websocketd
    mybatis——一级缓存、二级缓存
    mybatis学习——多对一和一对多查询
    XML文件存在中文注释报错问题( 3 字节的 UTF-8 序列的字节 3 无效)
    mybatis设置自动提交事务
    mybatis之Param注解
    mybatis学习——实现分页
    mybatis学习——日志工厂
    mybatis——解决属性名和数据库字段名不一致问题
  • 原文地址:https://www.cnblogs.com/linxiyue/p/4060434.html
Copyright © 2011-2022 走看看