Python+Django+SAE系列教程17-----authauth (认证与授权)系统1

      通过session,我们可以在多次浏览器请求中保持数据,接下来的部分就是用session来处理用户登录了。 当然,不能仅凭用户的一面之词,我们就相信,所以我们需要认证。

当然了,Django 也提供了工具来处理这样的常见任务(就像其他常见任务一样)。 Django 用户认证系统处理用户帐号,组,权限以及基于cookie的用户会话。这个系统一般被称为 auth/auth (认证与授权)系统。 这个系统的名称同时也表明了用户常见的两步处理。 我们需要:

1.     验证 (认证) 用户是否是他所宣称的用户(一般通过查询数据库验证其用户名和密码)

2.     验证用户是否拥有执行某种操作的 授权 (通常会通过检查一个权限表来确认)


根据这些需求,Django 认证/授权 系统会包含以下的部分:

§ 用户 :在网站注册的人

§ 权限 :用于标识用户是否可以执行某种操作的二进制(yes/no)标志

§  :一种可以将标记和权限应用于多个用户的常用方法

§ Messages : 向用户显示队列式的系统消息的常用方法

如果你已经用了admin工具(详见第6章),就会看见这些工具的大部分。如果你在admin工具中编辑过用户或组,那么实际上你已经编辑过授权系统的数据库表了。

在我们执行manage.py syncdb的时候,在命令行工具中,就已经根据向导创建了第一个用户,下面我们先来看看如何使用Django认证与授权系统做登陆和注销的功能。

首先我们先修改一下urls.py

from django.conf.urls import patterns, include, url
from django.contrib.auth.views import login, logout

# Uncomment the next two lines to enable the admin:
# from django.contrib import admin
# admin.autodiscover()

urlpatterns = patterns('',
    # Examples:
    # url(r'^$', 'Bidding.views.home', name='home'),
    # url(r'^Bidding/', include('Bidding.foo.urls')),

    # Uncomment the admin/doc line below to enable admin documentation:
    # url(r'^admin/doc/', include('django.contrib.admindocs.urls')),

    # Uncomment the next line to enable the admin:
    # url(r'^admin/', include(admin.site.urls)),
    url(r'^hello/$', 'Bidding.views.hello'),
    url(r'^time/$', 'Bidding.views.current_datetime'),
    url(r'^time/plus/(\d{1,2})/$', 'Bidding.views.hours_ahead'),
    url(r'^hello_base/$', 'Bidding.views.hello_base'),
    url(r'^request_test/$', 'Bidding.views.request_test'),
    url(r'^UsersSearch/$', 'Bidding.Users.views.search_form'),
    url(r'^search/$', 'Bidding.Users.views.search'),
    url(r'^ClassRoom/add/$', 'person.views.ClassroonAdd'),
    url(r'^ClassRoom/list/$', 'person.views.ClassroonList'),
    url(r'^ClassRoom/modify/(\d+)/$', 'person.views.ClassroonModify'),
    url(r'^ClassRoom/delete/(\d+)/$', 'person.views.ClassroonDelete'),
    url(r'^testPIC/$', 'Bidding.views.my_image'),
    url(r'^testPDF/$', 'Bidding.views.hello_pdf'),
    url(r'^testCookie/show/$', 'Bidding.views.show_cookie'),
    url(r'^testCookie/set/(\w+)/$', 'Bidding.views.set_cookie'),
    url(r'^testCookie/del/$', 'Bidding.views.del_cookie'),
    url(r'^testSession/show/$', 'Bidding.views.show_session'),
    url(r'^testSession/set/(\w+)/$', 'Bidding.views.set_session'),
    url(r'^testSession/del/$', 'Bidding.views.del_session'),
#url(r'^accounts/login/$',  login),
    url(r'^accounts/login/$',  login, {'template_name': 'login.html'}),
    url(r'^accounts/logout/$', logout),
                       
)

注意:login和logout函数是不需要我们写视图的,因为在urls.py的顶部我加入了:

fromdjango.contrib.auth.views import login, logout

也就是说这两个函数时Django默认的视图,下面的问题就出来了,如果视图的默认的,我们无从编辑,那么视图对应的模板呢?这个不用着急,在Djiango中,login对应的模板存放在: registragiton/login.html   ( 可以通过视图的额外参数  template_name   修改这个模板名称)。 这个表单必须包含  username   和  password   域。如下示例:一个简单的 template 看起来是这样的。

{% extends "base.html" %}

{% block content %}

  {% if form.errors %}
    <p class="error">用户名密码错误!</p>
  {% endif %}

  <form action="" method="post">
{% csrf_token %} 
    <label for="username">用户名:</label>
    <input type="text" name="username" value="" id="username">
    <label for="password">密码:</label>
    <input type="password" name="password" value="" id="password">

    <input type="submit" value="登录" />
    <input type="hidden" name="next" value="{{ next|escape }}" />
  </form>

{% endblock %}

如果用户登录成功,缺省会重定向到 /accounts/profile 。你可以提供一个保存登录后重定向URL的next隐藏域来重载它的行为。也可以把值以GET参数的形式发送给视图函数,它会以变量next的形式保存在上下文中,这样你就可以把它用在隐藏域上了。

logout视图有一些不同。 默认情况下它渲染 registration/logged_out.html 模板(这个视图一般包含你已经成功退出的信息)。视图中还可以包含一个参数 next_page 用于退出后重定向。


这时输入你之前创建的用户名密码,就可以登录了。为了以后的学习,我们先建立一个页面为登陆后的默认页:

 

新建welcom.html

{% extends "base.html" %}

{% block content %}

<p>欢迎访问本页面</p>
   <a href="../accounts/logout/">退出系统</a>


{% endblock %}

添加视图views.py

def welcom(request):
       return render_to_response('welcom.html', locals())

配置urls.py

from django.conf.urls import patterns, include, url
from django.contrib.auth.views import login, logout

# Uncomment the next two lines to enable the admin:
# from django.contrib import admin
# admin.autodiscover()

urlpatterns = patterns('',
    # Examples:
    # url(r'^$', 'Bidding.views.home', name='home'),
    # url(r'^Bidding/', include('Bidding.foo.urls')),

    # Uncomment the admin/doc line below to enable admin documentation:
    # url(r'^admin/doc/', include('django.contrib.admindocs.urls')),

    # Uncomment the next line to enable the admin:
    # url(r'^admin/', include(admin.site.urls)),
    url(r'^hello/$', 'Bidding.views.hello'),
    url(r'^time/$', 'Bidding.views.current_datetime'),
    url(r'^time/plus/(\d{1,2})/$', 'Bidding.views.hours_ahead'),
    url(r'^hello_base/$', 'Bidding.views.hello_base'),
    url(r'^request_test/$', 'Bidding.views.request_test'),
    url(r'^UsersSearch/$', 'Bidding.Users.views.search_form'),
    url(r'^search/$', 'Bidding.Users.views.search'),
    url(r'^ClassRoom/add/$', 'person.views.ClassroonAdd'),
    url(r'^ClassRoom/list/$', 'person.views.ClassroonList'),
    url(r'^ClassRoom/modify/(\d+)/$', 'person.views.ClassroonModify'),
    url(r'^ClassRoom/delete/(\d+)/$', 'person.views.ClassroonDelete'),
    url(r'^testPIC/$', 'Bidding.views.my_image'),
    url(r'^testPDF/$', 'Bidding.views.hello_pdf'),
    url(r'^testCookie/show/$', 'Bidding.views.show_cookie'),
    url(r'^testCookie/set/(\w+)/$', 'Bidding.views.set_cookie'),
    url(r'^testCookie/del/$', 'Bidding.views.del_cookie'),
    url(r'^testSession/show/$', 'Bidding.views.show_session'),
    url(r'^testSession/set/(\w+)/$', 'Bidding.views.set_session'),
    url(r'^testSession/del/$', 'Bidding.views.del_session'),
    url(r'^accounts/login/$',  login, {'template_name': 'login.html'}),
    url(r'^accounts/logout/$', logout),
    url(r'^welcom/$', 'Bidding.views.welcom'),                
)

建立这个页面,是为了登陆以后跳转到这里,而不是系统默认的/accounts/profile,因此我们要修改一下login.html的模板,在next隐藏域打上我们新建的这个页面的路径,如下:

{% extends "base.html" %}

{% block content %}

  {% if form.errors %}
    <p class="error">用户名密码错误!</p>
  {% endif %}

  <form action="" method="post">
{% csrf_token %} 
    <label for="username">用户名:</label>
    <input type="text" name="username" value="" id="username">
    <label for="password">密码:</label>
    <input type="password" name="password" value="" id="password">

    <input type="submit" value="登录" />
    <input type="hidden" name="next" value="../../welcome/" />
  </form>

{% endblock %}

在运行一下试试看,效果达到了吧!


正如我们上面所担心的,其实welcom/页面如果没有登陆其实也是可以访问的,不用着急Django为我们提供了非常简便的办法,我们只需要在对应的视图上面加上一句@login_required 就可以了:

@login_required
def welcom(request):
       return render_to_response('welcom.html', locals())

这就意味着本页面必须通过验证的用户才可以访问,注意一定要在头部加上

from django.contrib.auth.decorators import login_required

才可以哦!

我们在直接访问welcom/试验一下吧:



系统会自动定位到登陆页面,等我们登陆以后才会真正执行视图中的函数。

其实还有一种情况,就是虽然登陆了,但是一些关键的页面也不能让某些用户访问,这里就用到权限的管理了。下面我们就来重点讨论一下管理 Users, Permissions 和 Groups的过程:

首先我们先模仿

Python+Django+SAE系列教程13-----MySQL记录的添\删\

的例子制作一个用户标的基础数据库操作

首先配置urls.py:

from django.conf.urls import patterns, include, url
from django.contrib.auth.views import login, logout

# Uncomment the next two lines to enable the admin:
# from django.contrib import admin
# admin.autodiscover()

urlpatterns = patterns('',
    # Examples:
    # url(r'^$', 'Bidding.views.home', name='home'),
    # url(r'^Bidding/', include('Bidding.foo.urls')),

    # Uncomment the admin/doc line below to enable admin documentation:
    # url(r'^admin/doc/', include('django.contrib.admindocs.urls')),

    # Uncomment the next line to enable the admin:
    # url(r'^admin/', include(admin.site.urls)),
    url(r'^hello/$', 'Bidding.views.hello'),
    url(r'^time/$', 'Bidding.views.current_datetime'),
    url(r'^time/plus/(\d{1,2})/$', 'Bidding.views.hours_ahead'),
    url(r'^hello_base/$', 'Bidding.views.hello_base'),
    url(r'^request_test/$', 'Bidding.views.request_test'),
    url(r'^UsersSearch/$', 'Bidding.Users.views.search_form'),
    url(r'^search/$', 'Bidding.Users.views.search'),
    url(r'^ClassRoom/add/$', 'person.views.ClassroonAdd'),
    url(r'^ClassRoom/list/$', 'person.views.ClassroonList'),
    url(r'^ClassRoom/modify/(\d+)/$', 'person.views.ClassroonModify'),
    url(r'^ClassRoom/delete/(\d+)/$', 'person.views.ClassroonDelete'),
    url(r'^testPIC/$', 'Bidding.views.my_image'),
    url(r'^testPDF/$', 'Bidding.views.hello_pdf'),
    url(r'^testCookie/show/$', 'Bidding.views.show_cookie'),
    url(r'^testCookie/set/(\w+)/$', 'Bidding.views.set_cookie'),
    url(r'^testCookie/del/$', 'Bidding.views.del_cookie'),
    url(r'^testSession/show/$', 'Bidding.views.show_session'),
    url(r'^testSession/set/(\w+)/$', 'Bidding.views.set_session'),
    url(r'^testSession/del/$', 'Bidding.views.del_session'),
    url(r'^accounts/login/$',  login, {'template_name': 'login.html'}),
    url(r'^accounts/logout/$', logout,{'next_page':'/accounts/login'}),
    url(r'^welcom/$', 'Bidding.views.welcom'),
    url(r'^User/add/$', 'Bidding.Users.views.CreateUser'),
    url(r'^User/list/$', 'Bidding.Users.views.UserList'),
    url(r'^User/modify/(\d+)/$', 'Bidding.Users.views.UserModify'),
    url(r'^User/delete/(\d+)/$', 'Bidding.Users.views.UserDelete'),
)

添加视图,修改后的bidding/users/view.py是这样的:

# -*- coding: utf-8 -*-
from django.http import HttpResponse
from django.shortcuts import render_to_response
from django.template import RequestContext
from django.contrib.auth.models import User

def search_form(request):
    return render_to_response('Users/search_form.html')

def search1(request):
    if 'q' in request.GET:
        message = '您搜索的关键字是: %r' % request.GET['q']
    else:
        message = '请输入您要检索的内容'
    return HttpResponse(message)

def search(request):
    if 'q' in request.GET and request.GET['q']:
        q = request.GET['q']
        return render_to_response('Users/search_results.html',
            {'query': q})
    else:
        return render_to_response('Users/search_form.html', {'error': True})
    

def CreateUser(request):
    if request.POST.has_key('username')  and request.POST.has_key('password') and request.POST.has_key('email') :
        username = request.POST['username']
        password = request.POST['password']
        email = request.POST['email']
        user = User.objects.create_user(username=username,
                                        email=email,
                                        password=password)
        user.save()
        return render_to_response('Users/User_Add_results.html',
            {'username': username},context_instance=RequestContext(request))
    else:
        return render_to_response('Users/User_Add.html', {'error': True},context_instance=RequestContext(request))

def UserList(request):
        UserList=User.objects.all()
        return render_to_response('Users/User_List.html',
            {'UserList': UserList})


def UserDelete(request,id1):
    
    GetHost=request.get_host()
    try:  
        GetHTTP_REFERER = request.META['HTTP_REFERER']  
    except KeyError:  
        GetHTTP_REFERER = 'unknown'
        
    if GetHTTP_REFERER!='unknown' and GetHTTP_REFERER.find(GetHost)>0:
        user=User.objects.get(id=id1)
        old_name = user.username
        user.delete()
        return render_to_response('Users/User_Delete_results.html',{'name':old_name})
    else:
        return render_to_response('Users/Error.html')


def UserModify(request,id1):

    GetHost=request.get_host()
    try:  
        GetHTTP_REFERER = request.META['HTTP_REFERER']  
    except KeyError:  
        GetHTTP_REFERER = 'unknown'
        
    if GetHTTP_REFERER!='unknown' and GetHTTP_REFERER.find(GetHost)>0:
        user=User.objects.get(id=id1)
        old_username = user.username
        old_email = user.email
        old_password = user.password
        if request.POST.has_key('username')  and request.POST.has_key('email') and request.POST.has_key('password') :
            new_username = request.POST['username']
            new_email = request.POST['email']
            new_password = request.POST['password']
            user.username=new_username
            user.email=new_email
            user.set_password(new_password)
            #Django 在 ``django.contrib.auth`` 提供了2个函数: ``authenticate()``和 ``login()`` 。
            #如果通过给定的用户名和密码做认证,请使用 ``authenticate()`` 函数。
            #user = authenticate(username=username,password=old_password)
            #自己修改密码时首先验证旧密码是否正确
            #user.password=new_password  #这样不行的
            user.save()
            return render_to_response('Users/User_Modify_results.html',
                {'old_username': old_username,'old_email':old_email,'old_password':old_password,'new_username': new_username,'new_email':new_email,'new_password':new_password},context_instance=RequestContext(request))
        else:
            return render_to_response('Users/User_Modify.html', {'error': True,'id':id1,'username':old_username,'email':old_email,'password':old_password},context_instance=RequestContext(request))
    else:
        return render_to_response('Users/Error.html')

注意在修改和读取密码的时候:

 因为数据库中存储的django加密以后的密码,我们在读取的时候是一串加密后的字符串,这里不能够显示的表现出来,如果修改密码用简单的user.password=new_password,也是不行的,必须使用user.set_password(new_password)来修改密。#如果用户自己修改密码时首先验证旧密码是否正确,可以通过给定的用户名和密码做认证,请使用``authenticate()`` 函数,代码如下:记得要导入django.contrib.auth

<span style="font-weight: normal;">from django.contrib import auth

 user =authenticate(username=username,password=old_password)</span>

下面是一些模板,我把它们放在了Bidding/templates/Users中了

User_Add.html

<span style="font-weight: normal;"><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html>
<head>
    <title>数据库操作简单表的添加</title>
</head>
<body>
    <h1>这里是用户的添加页面</h1>
    {% if error %}
        <p style="color: red;">请输入用户名、邮箱和密码</p>
    {% endif %}
   <form action="" method="post">
   {% csrf_token %} 
        <table border="1" cellpadding="10">
          <tr>
            <td align="center">项目</td>
            <td align="center">内容</td>
          </tr>
          <tr>
            <td align="right">用户名:</td>
            <td><input type="text" name="username"></td>
          </tr>
          <tr>
            <td align="right">密码:</td>
            <td><input type="text" name="password"></td>
          </tr>
          <tr>
            <td align="right">邮箱:</td>
            <td><input type="text" name="email"></td>
          </tr>
          <tr>
            <td colspan="2"><input type="submit" value="添加"></td>
          </tr>
        </table>
  </form>
  
</body>
</html></span>

User_Add_results.html

<span style="font-weight: normal;"><html>
<head>
    <title>查询用户结果页</title>
</head>
<body>
    <table border="1" cellpadding="5"><tr>
      <td>用户:{{username}}添加成功 !</td></tr>
      <tr>
        <td><a href="http://127.0.0.1:8000/User/add/">点击返回</a></td>
      </tr>
    </table>
</body>
</html></span>

User_Delete_results.html

<span style="font-weight: normal;"><html>
<head>
    <title>查询用户结果页</title>
</head>
<body>
    <table border="1" cellpadding="5"><tr>
      <td>用户:{{name}}删除成功 !</td></tr>
      <tr>
        <td><a href="http://127.0.0.1:8000/User/list/">点击返回</a></td>
      </tr>
    </table>
</body>
</html>
</span>

User_List.html

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html>
<head>
    <title>用户管理</title>
</head>
<body>
    <h1>这里是User的管理页面</h1>
        <table border="1" cellpadding="10">
          <tr>
            <td align="center">序号</td>
            <td align="center">用户名</td>
            <td align="center">邮箱</td>
            <td align="center">操作</td>
          </tr>
          {% for myuser in UserList%}
          <tr>
            <td align="right">{{ myuser.id }}</td>
            <td align="right">{{ myuser.username }}</td>
            <td align="right">{{ myuser.email }}</td>
            <td align="right">
            <a href="../modify/{{ myuser.id }}">修改</a>
            <a href="../delete/{{ myuser.id }}">删除</a>
        
            </td>
          </tr>
          {% endfor %} 
        </table>
</body>
</html>

User_Modify.html

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html>
<head>
    <title>数据库操作简单表的修改</title>
</head>
<body>
    <h1>这里是User--{{username}}的修改页面</h1>
    {% if error %}
        <p style="color: red;">请输入班级名称和导师姓名</p>
    {% endif %}
    <form action="" method="post">
   {% csrf_token %} 
        <table border="1" cellpadding="10">
          <tr>
            <td align="center">项目</td>
            <td align="center">内容</td>
          </tr>
          <tr>
            <td align="right">用户名:</td>
            <td><input type="text" name="username" value="{{username}}"></td>
          </tr>
          <tr>
            <td align="right">邮箱:</td>
            <td><input type="text" name="email" value="{{email}}"></td>
          </tr>
		  <tr>
            <td align="right">密码:</td>
            <td><input type="text" name="password" value="{{password}}"></td>
          </tr>
          <tr>
            <td colspan="2">
            <input type="hidden" name="id" value="{{id}}">
            <input type="submit" value="修改">
            <input type="button" value="返回" onClick="location.href='../../list'">
            </td>
          </tr>
        </table>
  </form>
</body>
</html>

User_Modify_results.html

<html>
<head>
    <title>查询用户结果页</title>
</head>
<body>
    <table border="1" cellpadding="5"><tr>
      <td align="center"> </td>
      <td align="center">修改前</td>
      <td align="center">修改后</td>
      </tr>
      <tr>
        <td align="right">用户名:</td>
        <td align="right">{{old_username}}</td>
        <td align="right">{{new_username}}</td>
      </tr>
      <tr>
        <td align="right">邮箱:</td>
        <td align="right">{{old_email}}</td>
        <td align="right">{{new_email}}</td>
      </tr>
	   <tr>
        <td align="right">密码:</td>
        <td align="right">{{old_password}}</td>
        <td align="right">{{new_password}}</td>
      </tr>
      <tr>
        <td colspan="3" align="center">修改成功!</td>
      </tr>
      <tr>
        <td colspan="3" align="center"><a href="../../list/">点击返回</a></td>
      </tr>
    </table>
</body>
</html>

这样我们就做好了一个管理用户信息的页面了,用我们新添加的用户也可以登录之前的那个登录页面了。下面就是如何对这些用户设置具体的权限。


  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Bsphp软件管理系统是一套支持软件接口和用户会员平台以及支持做微型企业官网系统,CMS模板内容简单实用可以极快搭建好一个企业或者软件专题下载线上服务网站,后台界面简洁易用!Bsphp服服务端提供很多对外API接口可以实现客户端调用用户中心功能,从而实现控制软件开发软件授权使用,支持PC端,安卓,苹果系统,编程语言有C++,易语言,C#,VB,TC,Delphi,E4a,VC,JAVA,只要支持http协议就可以调用Bsphp客户端功能! 注意:软件需在后台-系统设置中点击开启前台cms,前台才可使用。 更新日志: Bsphp.v8.0.2优化 更新内容2018.3.16 更新优化显示充值账号 插件添加WEIBAPI接口 优化批量冻结BUG Bsphp.v8.0.1优化 更新内容2018.3.5 优化后台列表 优化列表全选 优化批量操作 Bsphp.v8 更新内容2018.1.30 1.更新优化细节 2.用户添加备注功能 3.优化代理能给制定代理制度卡制作>在用户中心>分配代理卡 4.API细节优化 5.接口加密进行优化 6.细节上的优化,根据用户反馈 7.更新C++ SDK演示 纯源码 7.7版本更新内容 重大更新 代理端添加代理可以添加下线 最多添加3级下线代理 代理平台可以注册用户 代理商可以控制下线的价格 代理可以个自己下线添加金额,与顶级代理用户分离 代理设置不可以登录用户中心,登录软件使用,设置为代理只可以在代理商平台登录使用 代理商可以直接给用户充值 代理显示钱单位为点 后台模式添加登录模式 扣点模式 代理模式添加卡模式 扣点模式 添加机器码注册API接口,用户可以卡模式定义一个串作为登录通过指定API 优化API接口 修复API timeout接口小bug 后台添加软件用户列表冻结功能,卡模式登录模式都可以使用 添加后台菜单自定义DIY功能,用户可以自定义后台菜单这样就可以定制个性化后台显示菜单,简单化显示 优化后台布局DIY 优化数据读写函数提高读取效率 优化BSPHP核心引擎加快php类的载入 修复前台验证不显示问题 修复个人中心URL大小写问题 优化模板设置功能 优化用户在线表的统计方式 添加输入模式 JOSN XML 添加加密RC4加密 添加登录/卡模式 口点的API接口 优化后台管理列表HTML代码优化 更新后台首页显示用户登录等信息的显示BUG 添加备注字段,在软件列表添加备注字段,通过API接口备注 优化批量操作管理,友情提示:使用前先备份数据库,批量操作慎用或少用! 优化了批量维护选择html代码BUG 批量维护软件账号添加冻结功能,多软件模式下可以冻结指定软件账号 添加购卡列表多种搜索字段功能5种过滤搜索 添加余额充值多种搜索字段功能5种过滤搜索 特别感谢 经过BSPHP大家庭努力还有各路网友支持不断完善网络客户端,BSPHP有你们将做得更好更便捷。 BSPHP感谢提供客户端、反馈BUG、吐槽不好用、感谢你们,我们到目前为止已经送出132个天使开发者称号等值商业用户永久版。 我们在这里承诺,BSPHP只要能够支持服务器支持绝不会涨价!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值