通過Flask_Login實現用戶驗證登錄,並通過login_required裝飾器來判斷用戶登錄狀態來判斷是否允許訪問視圖函數。
運行環境:
python3.5 Flask 0.12.2 Flask_Login 0.4.1 Flask-WTF 0.14.2 PyMySQL 0.8.0 WTForms 2.1 DBUtils 1.2
目錄結構:
直接看代碼,具體功能有注釋
Model/User_model.py
1 #創建一個類,用來通過sql語句查詢結果實例化對象用 2 class User_mod(): 3 def __init__(self): 4 self.id=None 5 self.username=None 6 self.task_count=None 7 self.sample_count=None 8 9 def todict(self): 10 return self.__dict__ 11 12 #下面這4個方法是flask_login需要的4個驗證方式 13 def is_authenticated(self): 14 return True 15 16 def is_active(self): 17 return True 18 19 def is_anonymous(self): 20 return False 21 22 def get_id(self): 23 return self.id 24 25 # def __repr__(self): 26 # return '<User %r>' % self.username
templates/login.html
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Title</title> 6 </head> 7 <body> 8 <div class="login-content"> 9 <form class="margin-bottom-0" action="{{ action }}" method="{{ method }}" id="{{ formid }}"> 10 {{ form.hidden_tag() }} 11 <div class="form-group m-b-20"> 12 {{ form.username(class='form-control input-lg',placeholder = "用戶名") }} 13 </div> 14 <div class="form-group m-b-20"> 15 {{ form.password(class='form-control input-lg',placeholder = "密碼") }} 16 </div> 17 <div class="checkbox m-b-20"> 18 <label> 19 {{ form.remember_me() }} 記住我 20 </label> 21 </div> 22 <div class="login-buttons"> 23 <button type="submit" class="btn btn-success btn-block btn-lg">登 錄</button> 24 </div> 25 </form> 26 </div> 27 28 29 </body> 30 </html>
User_dal/dal.py
1 import pymysql 2 from DBUtils.PooledDB import PooledDB 3 4 POOL = PooledDB( 5 creator=pymysql, # 使用鏈接數據庫的模塊 6 maxconnections=6, # 連接池允許的最大連接數,0和None表示不限制連接數 7 mincached=2, # 初始化時,鏈接池中至少創建的空閑的鏈接,0表示不創建 8 maxcached=5, # 鏈接池中最多閑置的鏈接,0和None不限制 9 maxshared=3, 10 # 鏈接池中最多共享的鏈接數量,0和None表示全部共享。PS: 無用,因為pymysql和MySQLdb等模塊的 threadsafety都為1,所有值無論設置為多少,_maxcached永遠為0,所以永遠是所有鏈接都共享。 11 blocking=True, # 連接池中如果沒有可用連接后,是否阻塞等待。True,等待;False,不等待然后報錯 12 maxusage=None, # 一個鏈接最多被重復使用的次數,None表示無限制 13 setsession=[], # 開始會話前執行的命令列表。如:["set datestyle to ...", "set time zone ..."] 14 ping=0, 15 # ping MySQL服務端,檢查是否服務可用。# 如:0 = None = never, 1 = default = whenever it is requested, 2 = when a cursor is created, 4 = when a query is executed, 7 = always 16 host='192.168.20.195', 17 port=3306, 18 user='root', 19 password='youpassword', 20 database='mytest', 21 charset='utf8' 22 ) 23 24 25 class SQLHelper(object): 26 27 @staticmethod 28 def fetch_one(sql,args): 29 conn = POOL.connection() #通過連接池鏈接數據庫 30 cursor = conn.cursor() #創建游標 31 cursor.execute(sql, args) #執行sql語句 32 result = cursor.fetchone() #取的sql查詢結果 33 conn.close() #關閉鏈接 34 return result 35 36 @staticmethod 37 def fetch_all(self,sql,args): 38 conn = POOL.connection() 39 cursor = conn.cursor() 40 cursor.execute(sql, args) 41 result = cursor.fetchone() 42 conn.close() 43 return result
User_dal/user_dal.py
1 from Model import User_model 2 from User_dal import dal 3 from User_dal import user_dal 4 class User_Dal: 5 persist = None 6 7 #通過用戶名及密碼查詢用戶對象 8 @classmethod 9 def login_auth(cls,username,password): 10 print('login_auth') 11 result={'isAuth':False} 12 model= User_model.User_mod() #實例化一個對象,將查詢結果逐一添加給對象的屬性 13 sql ="SELECT id,username,sample_count,task_count FROM User WHERE username ='%s' AND password = '%s'" % (username,password) 14 rows = user_dal.User_Dal.query(sql) 15 print('查詢結果>>>',rows) 16 if rows: 17 result['isAuth'] = True 18 model.id = rows[0] 19 model.username = rows[1] 20 model.sample_count = rows[2] 21 model.task_count = rows[3] 22 return result,model 23 24 #flask_login回調函數執行的,需要通過用戶唯一的id找到用戶對象 25 @classmethod 26 def load_user_byid(cls,id): 27 print('load_user_byid') 28 sql="SELECT id,username,sample_count,task_count FROM User WHERE id='%s'" %id 29 model= User_model.User_mod() #實例化一個對象,將查詢結果逐一添加給對象的屬性 30 rows = user_dal.User_Dal.query(sql) 31 if rows: 32 result = {'isAuth': False} 33 result['isAuth'] = True 34 model.id = rows[0] 35 model.username = rows[1] 36 model.sample_count = rows[2] 37 model.task_count = rows[3] 38 return model 39 40 #具體執行sql語句的函數 41 @classmethod 42 def query(cls,sql,params = None): 43 result =dal.SQLHelper.fetch_one(sql,params) 44 return result
denglu.py flask主運行文件
1 from flask import Flask,render_template,redirect 2 from flask_login import LoginManager,login_user,login_required,current_user 3 from flask_wtf.form import FlaskForm 4 from wtforms import StringField, PasswordField, BooleanField 5 from wtforms.validators import Length,DataRequired,Optional 6 from User_dal import user_dal 7 8 app = Flask(__name__) 9 10 #項目中設置flask_login 11 login_manager = LoginManager() 12 login_manager.init_app(app) 13 app.config['SECRET_KEY'] = '234rsdf34523rwsf' 14 15 #flask_wtf表單 16 class LoginForm(FlaskForm): 17 username = StringField('賬戶名:', validators=[DataRequired(), Length(1, 30)]) 18 password = PasswordField('密碼:', validators=[DataRequired(), Length(1, 64)]) 19 remember_me = BooleanField('記住密碼', validators=[Optional()]) 20 21 22 23 @app.route('/login',methods=['GET','POST']) 24 def login(): 25 form = LoginForm() 26 if form.validate_on_submit(): 27 username = form.username.data 28 password = form.password.data 29 result = user_dal.User_Dal.login_auth(username,password) 30 model=result[1] 31 if result[0]['isAuth']: 32 login_user(model) 33 print('登陸成功') 34 print(current_user.username) #登錄成功之后可以用current_user來取該用戶的其他屬性,這些屬性都是sql語句查來並賦值給對象的。 35 return redirect('/t') 36 else: 37 print('登陸失敗') 38 return render_template('login.html',formid='loginForm',action='/login',method='post',form=form) 39 return render_template('login.html',formid='loginForm',action='/login',method='post',form=form) 40 '''登錄函數,首先實例化form對象 41 然后通過form對象驗證post接收到的數據格式是否正確 42 然后通過login_auth函數,用username與password向數據庫查詢這個用戶,並將狀態碼以及對象返回 43 判斷狀態碼,如果正確則將對象傳入login_user中,然后就可以跳轉到正確頁面了''' 44 45 46 @login_manager.user_loader 47 def load_user(id): 48 return user_dal.User_Dal.load_user_byid(id) 49 ''' 50 load_user是一個flask_login的回調函數,在登陸之后,每訪問一個帶Login_required裝飾的視圖函數就要執行一次, 51 該函數返回一個用戶對象,通過id來用sql語句查到的用戶數據,然后實例化一個對象,並返回。 52 ''' 53 54 #登陸成功跳轉的視圖函數 55 @app.route('/t') 56 @login_required 57 def hello_world(): 58 print('登錄跳轉') 59 return 'Hello World!' 60 61 #隨便寫的另一個視圖函數 62 @app.route('/b') 63 @login_required 64 def hello(): 65 print('視圖函數b') 66 return 'Hello b!' 67 68 69 70 if __name__ == '__main__': 71 app.run()
簡單總結一下:
通過flask的form表單驗證數據格式
然后通過用戶名密碼從數據庫取用戶對象,將sql執行結果賦值給一個實例化的對象
將這個對象傳給login_user,
然后成功跳轉。
注意要寫一個load_user回調函數嗎,返回的是通過id取到的數據庫並實例化的對象的用戶對象。
這個回調函數每次訪問帶
login_required裝飾器的視圖函數都會被執行。
還有一個就是current_user相當於就是實例化的用戶對象,可以取用戶的其他屬性,注意,其他屬性僅限於sql語句查到的字段並添加給實例化對象的屬性。
代碼比較簡單,只是為了實現功能,敬請諒解,如有錯誤歡迎指出。
