Django进阶-auth集成认证模块
auth認證模塊是Django內置集成的一個用戶認證模塊。
auth認證模塊方法
方法 釋義
auth.authenticate() 認證校驗
auth.login(request,user) 封裝認證了的user對象
auth.logout(request) 將session數據都刪除,且cookie也失效
auth認證模塊示例
from django.shortcuts import render,redirect
from django.contrib import auth
from django.contrib.auth.decorators import login_required
def login(request):
if request.method == "POST":
user = request.POST.get("username")
pwd = request.POST.get("password")
user = auth.authenticate(username=user, password=pwd)
# auth認證校驗,如果校驗成功返回用戶名,否則返回空
if user:
auth.login(request, user)
# 封裝認證了的user對象
return redirect("index.html")
return render(request, "login.html")
auth認證模塊裝飾器使用
裝飾器,未登錄認證時無法訪問 index 默認跳轉到指定頁面,在setting中 配置LOGIN_URL = "跳轉的頁面名稱" 如:
LOGIN_URL = "login.html"
@login_required
def index(request):
print("登錄的用戶是:",request.user.username)
return render(request,"index.html")
auth認證模塊實例
目錄架構
MyDjango
APP
html
css
images
js
static
index.html
login.html
migrations
views
index.py
MyDjango
settings.py
urls.py
wsgi.py
db.sqlite3
manage.py
配置文件
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>wellcome</title>
</head>
<body>
{% csrf_token %}
<h1>wellcome index web !!!</h1>
<a href="login.html">退出</a>
</body>
</html>
login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form method="post" action="login.html">
{% csrf_token %}
用戶名:<input type="text" name = "username">
密碼: <input type="text" name = "password">
<input type="submit">
</form>
</body>
</html>
index.py
from django.shortcuts import render,redirect,HttpResponse
from django.contrib import auth
from django.contrib.auth.decorators import login_required
def login(request):
auth.logout(request)
if request.method == "POST":
user = request.POST.get("username")
pwd = request.POST.get("password")
print("用戶名:",user,"密碼:",pwd)
user = auth.authenticate(username=user, password=pwd)
# auth認證校驗,如果校驗成功返回用戶名,否則返回空
if user:
auth.login(request, user)
# 封裝認證了的user對象
return redirect("/index.html")
else:
return HttpResponse("登錄失敗,用戶或密碼錯誤!")
return render(request, "login.html")
@login_required
def index(request):
user = request.user.username
print("用戶",user,"登錄成功!")
return render(request, "index.html",{"user":user})
settings.py
TEMPLATES
'DIRS': [os.path.join(BASE_DIR, 'APP/html/static')]
STATIC_URL = '/static/'
STATICFILES_DIRS = (os.path.join(BASE_DIR,"APP/html/static"),)
STATIC_ROOT = 'APP/html'
LOGIN_URL = "login.html"
urls.py
from django.contrib import admin
from django.urls import path,re_path
from APP.views import index
urlpatterns = [
path('admin/', admin.site.urls),
re_path('^login.html$', index.login),
re_path('^index.html$', index.index),
]
服務運行
生成數據表
python manage.py makemigrations APP
python manage.py migrate
創建超級用戶用于登錄測試
python manage.py createsuperuser
服務運行
python manage.py runserver
復制代碼
可以看到只增加了一個類,這個類有個特點 1. 它實現了 InvocationHandler 接口 2. 它的 invoke 方法實現了我們的需求。InvocationHandler 是 Java 動態代理定義的一個接口,接口中定義了一個 invoke 方法,我們調用代理對象的任何方法都會變成對 FileWriterInvocationHandler 對象的 invoke 方法的調用, 在 invoke 方法中完成代理的功能并控制對真實對象的調用。如果看到你覺得一頭霧水,沒關系繼續向下看將豁然開朗。
到目前為止我們只看到新增了一個 InvocationHandler 接口的實現類,并沒有看到代理對象。之前說過之所以是動態代理是因為在運行時才創建代理類,因此我們需要編寫一個驅動程序,動態創建代理對象,完成動態代理的后半部分。
復制代碼
package com.cnblogs.duma.dp.proxy.dynamic;
import java.lang.reflect.Proxy;
public class DynamicProxyDriver {
public static void main(String[] args) {
/**
* Proxy.newProxyInstance 包括三個參數
* 第一個參數:定義代理類的 classloader,一般用被代理接口的 classloader
* 第二個參數:需要被代理的接口列表
* 第三個參數:實現了 InvocationHandler 接口的對象
* 返回值:代理對象
*/
Writer writer = (Writer) Proxy.newProxyInstance(
Writer.class.getClassLoader(),
new Class[www.baohuayule.com]{Writer.class},
new FileWriterInvocationHandler(new FileWriter())); //這就是動態的原因,運行時才創建代理類
try {
writer.write("file1.txt", "text"); //調用代理對象的write方法
} catch (Exception e) {
e.printStackTrace();
}
writer.write("file2.txt", new byte[]{}); //調用代理對象的write方法
}
}
復制代碼
最關的一步是 Proxy.newProxyInstance ,該調用會創建代理對象,該代理對象會將我們需要代理的接口(Writer)和 InvocationHandler 實現類關聯起來。這樣代理對象就會有 Writer 接口的 2 個方法,針對我們的業務邏輯調用過程為:調用代理對象 writer 的 write 方法寫數據 -> 轉到 FileWriterInvocationHandler 對象的 invoke 方法,判斷磁盤空間是否夠用 -> 拋出磁盤空間不足異常或調用 FileWriter 對象的 write 方法寫數據。在這里動態代理涉及到了 Writer 接口及其實現類、InvocationHandler 接口及其實現類、代理類。動態代理 UML 類圖如下:
可以看到代理類 Proxy 實現了 Writer 接口,因此可以調用 write 方法,同時代理類關聯 FileWriterInvocationHandler ,因此對 write 方法的調用會變成對 invoke 方法的調用。
至此,新的需求就完成了,我們結合代理模式談談此次需求變更我們用到了哪些好的設計原則。
1. 我們沒有在原有 FileWrite 實現類中修改代碼, 而是新增了 FileInvocationHandler 實現新需求,這符合設計原則中的開閉原則,即:對擴展開發對修改封閉。改動現有代碼容易影響已有的正常代碼
2. 我們增加代理之后只是把 Writer writer = new FileWriter() 改為 Writer writer = Proxy.newProxyInstance(...),由于都繼承了 Writer 接口,因此不需要修改 writer 的類型, 這符合面向接口的設計原則,讓我們盡量少的改動現有代碼
動態代理還有一個重要的應用場景,我們可以在 invoke 方法中把待調用的方法名(method)和參數(args)發送到遠程服務器,在遠程服務器中完成調用并返回一個結果,這其實就是 RPC (remote procedure call),即:遠程過程調用。我在閱讀 Hadoop 源碼過程中發現 Hadoop RPC 將動態代理技術應用在上述場景中。
遠程代理
個人覺得上述動態代理第二個應用場景算是遠程代理的一個特例,因為遠程代理不一定非要動態創建代理對象。接下來我們以 Java RMI 為例, 簡單看下遠程代理。RMI(remote method invocation)即:遠程方法調用,與 RPC 類似,可以讓我們像調用 Java 本地方法一樣,調用遠程的方法。這里就需要一個代理對象,代理對象實現了本地的接口,其中序列化/反序列化以及網絡傳輸都在代理對象中實現, 對我們透明,這也是控制了我們對遠程對象的訪問。代碼如下:
復制代碼
import java.rmi.Remote;
import java.rmi.RemoteException;
/**
* 定義一個接口,接口中的方法要在遠程調用
*/
public interface MyRemote extends Remote {
public String sayHello(www.gouyiflb.cn/ ) throws RemoteException;
}
復制代碼
復制代碼
import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
/**
* 定義一個接口的遠程實現類
* 為了讓遠程對象擁有 “遠程的” 功能,需要繼承 UnicastRemoteObject 類
*/
public class MyRemoteImpl extends UnicastRemoteObject implements MyRemote {
protected MyRemoteImpl() throws RemoteException {
}
/**
* 客戶端通過 rmi 代理對象調用 sayHello 方法,將會進入到此方法
* @return
* @throws RemoteException
*/
@Override
public String sayHello(www.365soke.com) throws RemoteException {
System.out.println("req from client.");
return "Server says, 'Hey'";
}
/**
* 啟動遠程進程的 main 方法
* @param args
*/
public static void main(String[www.lezongyule.com] args) {
try {
MyRemote service = new MyRemoteImpl(www.shengyunyule.cn);
Naming.rebind("RemoteHello", service); //將服務名和對應的服務進行綁定,客戶端會根據 RemoteHello 找到遠程服務
} catch (RemoteException e) {
e.printStackTrace();
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
}
復制代碼
這樣我們的遠程服務已經寫好了,還需要做以下 3 個工作來啟動遠程服務
1. 生成客戶端代理類,需要在 MyRemoteImpl.class 所在的目錄中執行 rmic MyRemoteImpl 命令,將會生成 MyRemoteImpl_Stub.class 類。首先,rmic 命令是 jdk 自帶命令,所在的目錄與 java 和 javac 所在的目錄一樣;其次,我用的 Idea 創建的普通 Java 工程,我的 MyRemoteImpl.class 文件在“E:\backends\java-backends\java-ex\out\production\java-ex”目錄中,以我的工程為例,路徑以及命令執行如下:
E:\backends\java-backends\java-ex\out \www.yun-shengyl.com production\java-ex>rmic MyRemoteImpl
2. 啟動 rmiregistry,為了遠程服務可以注冊服務名,在我們的 class 所在的目錄(“項目目錄\out\production\java-ex”)中執行 rmiregistry 命令
E:\backends\java-backends\java-ex\out\production\java-ex>rmiregistry
3. 運行 MyRemoteImpl 類,啟動遠程服務進程
繼續編寫客戶端訪問代碼,客戶端代碼主要是找到剛剛注冊的 RemoteHello 遠程服務,并獲得代理對象,調用代理對象上的方法。我們可以在同一個工程下,創建 MyRemoteClient 類
復制代碼
import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
public class MyRemoteClient {
public static void main(String[www.suoLaiervip.com] args) {
try {
/**
* 找到遠程服務,并返回代理對象
* 該代理對象就是 MyRemoteImpl_Stub 且實現了 MyRemote 接口
*/
MyRemote service = (MyRemote) Naming.lookup("rmi://127.0.0.1/RemoteHello");
/**
* 調用代理對象的 sayHello 方法,便會通過代理將調用發送到遠程服務進程并返回結果
*/
String ret = service.sayHello();
System.out.println(ret);
} catch (RemoteException e) {
e.printStackTrace(www.qwert888.com/);
} catch (NotBoundException e) {
e.printStackTrace();
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
}
復制代碼
我們可以直接運行 MyRemoteClient 類,可以看到在剛啟動的 MyRemoteImpl 進程中,控制臺打印了
req from client.
在 MyRemoteClient 進程的控制臺中打印了
Server says, 'Hey'
至此我們的遠程代理已經介紹完畢。
虛擬代理
虛擬代理是作為創建開銷大的對象的替身。舉一個我們常見的例子,在 Web 開發或者移動端開發的時候經常會用到 Image 組件,Image 組件一般要傳入一個 URL 參數,從網絡上下載圖片到本地展示。假設這個組件要等到圖片下載完成才有顯示,那如果圖片較大或者網絡較慢,給用戶造成不好的體驗。解決方法是我們可以先顯示一個 loading 狀態的默認的本地圖片,當遠程圖片下載完成后重新渲染,替換掉當前的 laoding 狀態的圖片。用虛擬代理來實現這個技術就可以定義一個 ImageProxy 類型,在該類中初始時候先展示一個默認圖片,啟動線程創建 Image 對象,Image 對象創建完畢,再重新渲染,替換默認圖片。虛擬代理也是控制了對 Image 對象的訪問。
總結
本章主要介紹了代理模式,并且我們看到了代理模式常用的幾種變形,同時也接觸了面向對象的基本的設計原則
動態代理 - 程序運行時動態地創建代理對象,所有的對代理對象方法的調用都會變成對 InvocationHandler 的 invoke 方法的調用
遠程代理 - 本地調用代理對象訪問遠程的方法,無需關心網絡通信細節,跟調用本地方法一樣
虛擬代理 - 為了創建開銷大的對象而存在
可以看到代理模式最核心就是控制,代理對象的目的就是控制對真實對象的訪問。
轉載于:https://www.cnblogs.com/qwangxiao/p/10638430.html
總結
以上是生活随笔為你收集整理的Django进阶-auth集成认证模块的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 华为换屏多少钱啊?
- 下一篇: 试管婴儿促排卵卵巢扭转症状