BBS(仿博客園系統)項目05(後臺管理功能實現:文章添加、富文本編輯器使用、xss攻擊、BeautifulSoup4模塊、富文本編輯器上傳圖片、修改頭像)

摘要css

  • 佈局框架搭建
  • 隨筆添加
  • 後臺管理富文本編輯器KindEditor
  • xss攻擊
  • 文章簡介的截取,BeautifulSoup4模塊
  • 富文本編輯器上傳圖片
  • 頭像修改

1、後臺管理框架佈局搭建

 後臺管理佈局框架分析:導航條、左側功能區、右側主要功能顯示和實現區html

實現:前端

導航條:使用bootstrap模板:JavaScript>>導航條jquery

左側:使用bootstrap模板:組件>>列表組bootstrap

右側:使用bootstrap模板:JavaScript>>標籤頁後端

新建後臺管理路由(注意放在站點路由上面)框架

url(r'^backend/', views.backend),

views.py視圖函數:xss

@login_required
def backend(request):
    user_obj = request.user
    article_list = models.Article.objects.filter(blog=user_obj.blog)
    return render(request, 'backend/backend.html', locals())

渲染後臺管理頁面(單獨在templates文件夾下建立後臺管理文件夾backend,而後在此文件夾下新建backend.html)編輯器

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>後臺管理</title>
    <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
    <link rel="stylesheet" href="/static/bootstrap-3.3.7-dist/css/bootstrap.min.css">
    <script src="/static/bootstrap-3.3.7-dist/js/bootstrap.min.js"></script>
    <style>
        #top_left {
            font-weight: bold;
            font-size: 24px;
            color: black;
        }

        #top_title {
            color: blue;
            font-size: 18px;
            font-weight: bold;
            font-family: "微軟雅黑 Light";
        }
    </style>
    {% block css %}

    {% endblock %}
</head>
<body>
{#後臺管理導航條#}
<nav class="navbar navbar-default">
    <div class="container-fluid">
        <div class="navbar-header">
            <button type="button" class="navbar-toggle collapsed" data-toggle="collapse"
                    data-target="#bs-example-navbar-collapse-5" aria-expanded="false">
                <span class="sr-only">Toggle navigation</span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
            </button>
            <a class="navbar-brand" href="/home/" id="top_left">博客園後臺管理</a>
            <p class="navbar-text" id="top_title">{{ request.user.blog.blog_title }}</p>
        </div>
        <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-5">
            <p class="navbar-text navbar-right">
                <a href="/{{ request.user.username }}/" class="navbar-link">{{ request.user.username }}</a>
            </p>
        </div>
    </div>
</nav>
{#            <a class="navbar-brand" href="#" id="top_left">博客園後臺管理</a>#}
{##}
{#                <li><a id="top_title" href="">{{ request.user.blog.blog_title }}</a></li>#}
{#                <li><a id="top_right" href="#">{{ request.user.username }}</a></li>#}

<div class="container-fluid">
    <div class="row">
        {# 後臺管理左側快捷入口占用2個柵格#}
        {#    左側信息展現:須要參數:tag_list category_list date_list user_obj#}
        <div class="col-md-2 col-sm-2 col-xs-3">
            <div class="list-group">
                <li class="list-group-item list-group-item-info">操做</li>
                <a href="/add_article/" class="list-group-item">添加新隨筆</a>
                <a href="#" class="list-group-item">草稿箱</a>
                <a href="#" class="list-group-item">添加新文章</a>
                <a href="#" class="list-group-item">其它...</a>
            </div>
            <hr>
            <div class="list-group">
                <li class="list-group-item list-group-item-warning">分類</li>
                <a href="#" class="list-group-item">編輯分類</a>
                <a href="#" class="list-group-item">全部分類</a>
                <a href="#" class="list-group-item">其它...</a>
            </div>
        </div>
        {# 後臺管理右側管理主要內容展現區佔用10個柵格#}
        {#      右側文章列表須要參數:article_list#}
        <div class="col-md-10 col-sm-10 col-xs-9">
            {% block content %}
                <div>
                    <!-- Nav tabs -->
                    <ul class="nav nav-tabs" role="tablist">
                        <li role="presentation" class="active"><a href="#article" aria-controls="home" role="tab"
                                                                  data-toggle="tab">隨筆</a></li>
                        <li role="presentation"><a href="#profile" aria-controls="profile" role="tab" data-toggle="tab">文章</a>
                        </li>
                        <li role="presentation"><a href="#messages" aria-controls="messages" role="tab"
                                                   data-toggle="tab">評論</a></li>
                        <li role="presentation"><a href="#settings" aria-controls="settings" role="tab"
                                                   data-toggle="tab">設置</a></li>
                    </ul>
                    <!-- Tab panes -->
                    <div class="tab-content">
                        <div role="tabpanel" class="tab-pane active" id="article">
                                <table class="table table-hover table-striped">
                                    <thead>
                                        <tr>
                                            <th>標題</th>
                                            <th class="text-center">發佈時間</th>
                                            <th class="text-center">評論數</th>
                                            <th class="text-center">點贊數</th>
                                            <th>操做</th>
                                            <th>操做</th>
                                        </tr>
                                    </thead>
                                    <tbody>
                                        {% for article in article_list %}
                                            <tr>
                                                <td><a href="/{{ article.blog.userinfo.username }}/article/{{ article.pk }}/">{{ article.title }}</a></td>
                                                <td class="text-center">{{ article.create_time|date:'Y-m-d' }}</td>
                                                <td class="text-center">{{ article.comment_num }}</td>
                                                <td class="text-center">{{ article.up_num }}</td>
                                                <td><a href="">編輯</a></td>
                                                <td><a href="">刪除</a></td>
                                            </tr>
                                        {% endfor %}
                                    </tbody>
                                </table>
                        </div>
                        <div role="tabpanel" class="tab-pane" id="profile">...</div>
                        <div role="tabpanel" class="tab-pane" id="messages">...</div>
                        <div role="tabpanel" class="tab-pane" id="settings">...</div>
                    </div>
                </div>
            {% endblock %}
        </div>
    </div>
</div>
{% block js %}

{% endblock %}
</body>
</html>

大體效果:函數

2、添加新隨筆

 先來一頓操做:

建路由:

url(r'^add_article/', views.add_article),

渲染頁面:繼承後臺管理主頁面

{% extends 'backend/backend.html' %}
{% block css %}
    <style>
        #title {
            margin-top: 5px;
            background-color: rgba(35,206,235,0.2);
            height: 22px;
            border-top: 1px gray solid;
            border-bottom: 1px gray dashed;
        }
    </style>

{% endblock %}
{% block content %}
<div>
<p id="title">添加隨筆</p>
<p>標題
    <input type="text" class="form-control">
</p>
</div>

視圖函數:

def add_article(request):
    return render(request, 'backend/add_article.html')

而後就能夠在上面的基礎上繼續進行:

富文本編輯器KindEditor的使用

下載該插件後,解壓,將其文件夾複製到static文件夾下

 

使用KindEditor須要藉助textarea輸入框,因此須要在添加隨筆處添加一個textarea框

BeautifulSoup4模塊

①表單在提交後,後端須要對文章進行截取一部分做爲文章的摘要desc,若是直接對提交的內容content進行切片的話得不到文章的文字內容,由於咱們經過富文本編輯器提交的內容實際上都是一行行html代碼,同時若是這段代碼中存在js腳本的話,有可能會存在xss腳本攻擊,這裏就須要對隨筆內容進行過濾

②先參考一下博客園處理xss攻擊的方式:

<script>alert(123)</script>,更新後再打開

能夠看出博客園的內部將此段代碼給加了代碼,讓js腳本無法生效,同時將隨筆保存再看發現這段代碼被認爲刪除了。

因此:

博客園處理xss攻擊方法:將敏感標籤自動添加內容,讓其失效,在後端處理時直接過濾掉敏感標籤,將其刪除。

引入一個模塊BeautifulSoup4:能夠過濾js腳本和拿到content內的文本內容,再進行切分。

先安裝模塊
pip3 install beautifulsoup4

# 這裏強調一點:必定要下官方推薦的beautifulsoup4版本,由於beautifulsoup3版本已經中止開發

富文本編輯器上傳圖片

經過富文本編輯器上傳圖片須要再開一個路由進行處理上傳的圖片

url(r'^upload_img/', views.upload_img),

 視圖函數upload_img:

def upload_img(request):
    if request.method == 'POST':
        # 前端富文本編輯器上傳的圖片key值叫imgFile,拿到文件對象
        img_obj = request.FILES.get('imgFile')
        print(img_obj.name,type(img_obj.name))
        # 手動拼接文件存放路徑,該文件應該存入media文件夾
        path = os.path.join(settings.BASE_DIR, 'media', 'article_img')
        # 判斷當前路徑是否存在,若是不不存在,則建立文件夾
        if not os.path.exists(path):
            os.mkdir(path)
        # 能夠經過img_obj.name,拿到這個文件對象的文件名,而後在拼接文件的路徑,用於保存寫入
        file_path = os.path.join(path, img_obj.name)
        with open(file_path, 'wb') as f:
            for line in img_obj:
                f.write(line)
        # 這裏須要注意富文本編輯器上傳圖片接收的響應數據格式規定是如下這種形式:
        """
            //成功時
            {
                    "error" : 0,
                    "url" : "http://www.example.com/path/to/file.ext"
            }
            //失敗時
            {
                    "error" : 1,
                    "message" : "錯誤信息"
            }
        """
        back_dic = {
            'error': 0,
            # 這個url就是前端能夠經過路由直接訪問到的文件路徑,這樣作的目的是編輯上傳一個圖片,編輯器確定須要
            # 拿到該圖片渲染到頁面上。
            'url': '/media/article_img/%s' % img_obj.name
        }
        return JsonResponse(back_dic)

3、修改頭像:

相關文章
相關標籤/搜索