1. 程式人生 > >自定義使用者和認證 中介軟體 檔案上傳/oss 圖片驗證碼

自定義使用者和認證 中介軟體 檔案上傳/oss 圖片驗證碼

自定義使用者

寫一個繼承自AbstractUser的類,然後追加自己需要的欄位

在settings.py加入AUTH_USER_MODEL = 'app的名字.使用者類'

自定義使用者認證

步驟

在app的目錄下新鍵一個檔案 auth.py

寫一個繼承自ModeBackend

複寫authenticate函式(一個是找人,一個是校驗密碼)

在settings.py裡設定:AUTHENTICATION_BACKENDS="app的名字.檔名字.類"

使用和原生認證是一樣的

例子:

使用者的登入,註冊不做了,使用Django shell建立一個使用者

登入:使用者名稱 手機號

寫一個測試使用者是否登入的API

自定義認證類的具體實現

1 找人

	1.1 使用使用者名稱搜尋

	1.2 再按照電話號搜尋

2 校驗密碼

	如果通過,返回user物件 否則返回None

from django.contrib.auth.backends import ModelBackend

from .models import MyUser


class MyBackend(ModelBackend):

    def authenticate(self, request, username=None, password=None, **kwargs):
        # 找人
        print("進入函式")
        try:
            user = MyUser.objects.get(username=username)
            print("沒找到")
        except Exception:
            try:
                user = MyUser.objects.get(phone=username)
                print(user.username, "找到了")
            except Exception as e:
                print(username, e)
                return None
        print("拿到使用者",user.username)
        # 密碼校驗
        if user.check_password(password):
            return user
        else:
            return None

自定義中介軟體

在中介軟體進行使用者名稱的判斷 滿足條件直接返回

中介軟體應用: 我們可以做反爬蟲,可以做日誌統計,做錯誤統計,做快取

實現:

from django.http import HttpResponse, HttpResponseForbidden
from django.utils.deprecation import MiddlewareMixin


class YJMiddleWare(MiddlewareMixin):

    def process_request(self, request):

        # name = request.GET.get("name")
        # if name == "tom":
        #     return HttpResponse("恭喜獲得特斯拉一輛")
        # elif name == "ada":
        #     return HttpResponse("特斯拉模型一輛")
        # elif name == "班長":
        #     return HttpResponse("咖妃")
        black_ips = [
            "124.160.17.98", "101.68.87.26"
        ]
        # 獲取IP
        ip = request.META.get("REMOTE_ADDR")
        print(ip)
        if ip in black_ips:
            return HttpResponseForbidden("黑名單成員 無法訪問")
        else:
            return HttpResponse("歡迎進入真人賭場,體驗美女荷官")

在settings.py里加入

MIDDLEWARE = [
    。。。。
    'MiddleWares.MyAOP.YJMiddleWare' # 目錄名.檔名.類名
]

上傳檔案

在models.py

class Book(models.Model):
    name = models.CharField(
        max_length=40
    )
    icon = models.ImageField(
        upload_to="icons" # 指定檔案儲存的路徑名 系統自動建立
    )

在settings.py 加入

 配置上傳檔案目錄
MEDIA_ROOT = os.path.join(BASE_DIR, "static/uploads")

views.py

def create_book_v1(req):
     # 解析引數
    name = req.POST.get("name")
    myfile = req.FILES.get("icon")

    # 例項化一個數據
    book = Book.objects.create(
        name=name,
        icon=myfile
    )
    return HttpResponse("ok")

如果想訪問圖片 需要自己拼接url

book = Book.objects.all().first()
        # 拼接圖片的網路路徑
        icon_url = "http://{}/static/uploads/{}".format(
            req.get_host(), #獲取訪問的域名加埠
            book.icon.url  #圖片的路徑字串
        )

生成隨機檔名

得到uuid字串

例項化md5

md5進行加密

得到32位16進位制的字串

import uuid
import hashlib
import random

def get_unique_str():
    # 得到一個uuid的字串
    uuid_str = str(uuid.uuid4()).encode("utf-8")
    # 例項化md5
    md5 = hashlib.md5()

    # 進行加密
    md5.update(uuid_str)
    # 返回32位的十六進位制資料
    return md5.hexdigest()

上傳檔案實現2

def create_book_v2(req):
    if req.method == "GET":
        return render(req, "mybook.html")
    else:
        # 拿到引數
        name = req.POST.get("name")
        myfile = req.FILES.get("icon")

        # 檔案路徑
        filename = get_unique_str() + "." + myfile.name.split(".")[-1]
        filepath = os.path.join(settings.MEDIA_ROOT, filename)
        f = open(filepath, "wb")
        print(filename)
        for i in myfile.chunks():
            f.write(i)
        f.close()
        return HttpResponse("ok")

檔案上傳到oss
用的阿里雲

def upload_to_oss(req):
    import oss2
    endpoint = 'http://oss-cn-shanghai.aliyuncs.com'
    access_key_id = 'LTA#########V9jSq'
    access_key_secret = '7uXYe##############AWFkxIw'
    bucket_name = 'share-msg'
    bucket_name_host = "share-##Bucket 域名##ncs.com"
    # 生成一個認證物件
    auth = oss2.Auth(access_key_id, access_key_secret)

    bucket = oss2.Bucket(auth, endpoint, bucket_name)

    #獲取檔案
    f = req.FILES.get("icon")
    # StringIO BytesIO
    from io import BytesIO
    # 例項化io
    buf = BytesIO()
    # 寫入到記憶體
    for i in f.chunks():
        buf.write(i)
    #     調整指標到開頭
    buf.seek(0)

    # 上傳
    filename = get_unique_str() + "." + f.name.split(".")[-1]
    bucket.put_object(filename, buf.getvalue())
    print(filename)
    file_url = "https://" + bucket_name_host + "/" + filename
    # 可以考慮把檔案存到資料庫
    return HttpResponse(file_url)

StringIO

在記憶體的緩衝中 操作資料 和操作檔案是類似的 也有指標的概念

驗證碼

pip install Pillow

需要:畫布 畫筆 和字型

def get_confirm_code(req):

    from PIL import Image, ImageDraw, ImageFont
    from io import BytesIO

#     例項化一個畫布
    img_size = (150,70)
    img_color = get_random_color()
    img = Image.new("RGB", img_size, img_color)

#     例項化一個畫筆
    draw = ImageDraw.Draw(img)
    code_xy = (20, 20)
    # code_color = (0, 255, 0)

    # 例項化一個字型
    font_path = os.path.join(settings.STATICFILES_DIRS[0], "fonts/ADOBEARABIC-BOLD.OTF")
    font_size = 30
    font = ImageFont.truetype(font_path, font_size)

    # 畫一個字母
    # draw.text(code_xy,"L", font=font, fill=code_color)
    # draw.text(code_xy, "O", font=font, fill=code_color)

    source = "zxcvbnmasdfghjklqwertyuiop1234567890ZXCVBNMASDFGHJKLQWERTYUIOP"
    # 用來儲存 我們生成的隨機字元
    res = ""
    for i in range(4):
    #     隨機出一個字母
        code_color = get_random_color()
        index = random.randint(0, len(source))
        my_str = source[index]
        res += my_str
        draw.text((20+30*i, 20), my_str, fill=code_color, font=font)

    # 畫點
    for i in range(100):
        x = random.randint(0, 150)
        y = random.randint(0, 70)
        draw.point((x, y), fill=get_random_color())
        # width = random.randint(0, 100)
        # draw.line((20, 65), fill=(255, 255, 255), width=50)

    buf = BytesIO()
    # 儲存
    img.save(buf, "png")
    del draw

    # 儲存的session
    req.session["verify_code"] = res
    return HttpResponse(buf.getvalue(), content_type="image/png")

應用

def my_login_v1(req):
    if req.method == "GET":
        return render(req, "my_login.html")
    else:
        code = req.POST.get("code")
        server_code = req.session.get("verify_code")
        # 將使用者傳入的和系統session儲存的字元都轉小寫 然後做比較
        if code and len(code) > 0 and code.lower() == server_code.lower():
            return HttpResponse("ok")
        else:
            return HttpResponse("no ok")

前端:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="http://libs.baidu.com/jquery/1.10.2/jquery.min.js"></script>

    <script>
        $(function () {
            $("#myimg").click(function () {
                console.log("呼叫")
                $(this).attr("src", "/t06/img" + Math.random());
            })
        })
    </script>
</head>
<body>
<form action="/t06/my_login" method="post">
    {% csrf_token %}
    <img src="/t06/img" alt="" id="myimg">
    <br>
    <input type="text" name="code" placeholder="請輸入驗證碼(忽略大小寫)">
    <br>
    <input type="submit" value="驗證">
</form>
</body>
</html>